blob: dd3ca5bb3ce2c76133612a80ee953ef1f66c0579 [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 }
Jim Carrollf452d542017-01-27 16:08:59 +00001315
1316 /* Default route sanity check */
paul718e3742002-12-13 20:15:29 +00001317 if (packet->version == RIPv2
Jim Carrollf452d542017-01-27 16:08:59 +00001318 && (rte->mask.s_addr == 0)
1319 && (rte->prefix.s_addr != 0))
1320 {
1321 if (IS_RIP_DEBUG_EVENT)
1322 zlog_warn ("Malformed route, zero netmask "
1323 "with non-zero addr - dropping route!");
1324 rip_peer_bad_route (from);
1325 continue;
1326 }
1327
paul718e3742002-12-13 20:15:29 +00001328 /* Routing table updates. */
paulc49ad8f2004-10-22 10:27:28 +00001329 rip_rte_process (rte, from, ifc->ifp);
paul718e3742002-12-13 20:15:29 +00001330 }
1331}
1332
paula4e987e2005-06-03 17:46:49 +00001333/* Make socket for RIP protocol. */
paulf69bd9d2005-06-03 18:01:50 +00001334static int
paul2c61ae32005-08-16 15:22:14 +00001335rip_create_socket (struct sockaddr_in *from)
paula4e987e2005-06-03 17:46:49 +00001336{
1337 int ret;
1338 int sock;
1339 struct sockaddr_in addr;
paulf69bd9d2005-06-03 18:01:50 +00001340
paul2c61ae32005-08-16 15:22:14 +00001341 memset (&addr, 0, sizeof (struct sockaddr_in));
1342
1343 if (!from)
paulf69bd9d2005-06-03 18:01:50 +00001344 {
paulf69bd9d2005-06-03 18:01:50 +00001345 addr.sin_family = AF_INET;
1346 addr.sin_addr.s_addr = INADDR_ANY;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001347#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001348 addr.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001349#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
jardin38d3c162005-10-19 19:29:59 +00001350 } else {
1351 memcpy(&addr, from, sizeof(addr));
paulf69bd9d2005-06-03 18:01:50 +00001352 }
1353
paul2c61ae32005-08-16 15:22:14 +00001354 /* sending port must always be the RIP port */
1355 addr.sin_port = htons (RIP_PORT_DEFAULT);
1356
paula4e987e2005-06-03 17:46:49 +00001357 /* Make datagram socket. */
1358 sock = socket (AF_INET, SOCK_DGRAM, 0);
1359 if (sock < 0)
1360 {
1361 zlog_err("Cannot create UDP socket: %s", safe_strerror(errno));
1362 exit (1);
1363 }
1364
1365 sockopt_broadcast (sock);
1366 sockopt_reuseaddr (sock);
1367 sockopt_reuseport (sock);
paula4e987e2005-06-03 17:46:49 +00001368#ifdef RIP_RECVMSG
1369 setsockopt_pktinfo (sock);
1370#endif /* RIP_RECVMSG */
Stephen Hemminger78b31d52009-07-21 16:27:26 -07001371#ifdef IPTOS_PREC_INTERNETCONTROL
1372 setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
1373#endif
paula4e987e2005-06-03 17:46:49 +00001374
1375 if (ripd_privs.change (ZPRIVS_RAISE))
1376 zlog_err ("rip_create_socket: could not raise privs");
paulf69bd9d2005-06-03 18:01:50 +00001377 setsockopt_so_recvbuf (sock, RIP_UDP_RCV_BUF);
1378 if ( (ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr))) < 0)
1379
paula4e987e2005-06-03 17:46:49 +00001380 {
1381 int save_errno = errno;
1382 if (ripd_privs.change (ZPRIVS_LOWER))
1383 zlog_err ("rip_create_socket: could not lower privs");
paul2c61ae32005-08-16 15:22:14 +00001384
1385 zlog_err("%s: Can't bind socket %d to %s port %d: %s", __func__,
1386 sock, inet_ntoa(addr.sin_addr),
1387 (int) ntohs(addr.sin_port),
1388 safe_strerror(save_errno));
1389
paulf69bd9d2005-06-03 18:01:50 +00001390 close (sock);
paula4e987e2005-06-03 17:46:49 +00001391 return ret;
1392 }
paulf69bd9d2005-06-03 18:01:50 +00001393
paula4e987e2005-06-03 17:46:49 +00001394 if (ripd_privs.change (ZPRIVS_LOWER))
1395 zlog_err ("rip_create_socket: could not lower privs");
1396
1397 return sock;
1398}
1399
paulc49ad8f2004-10-22 10:27:28 +00001400/* RIP packet send to destination address, on interface denoted by
1401 * by connected argument. NULL to argument denotes destination should be
1402 * should be RIP multicast group
1403 */
pauldc63bfd2005-10-25 23:31:05 +00001404static int
paulc49ad8f2004-10-22 10:27:28 +00001405rip_send_packet (u_char * buf, int size, struct sockaddr_in *to,
1406 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001407{
paul931cd542004-01-23 15:31:42 +00001408 int ret, send_sock;
paul718e3742002-12-13 20:15:29 +00001409 struct sockaddr_in sin;
paulc49ad8f2004-10-22 10:27:28 +00001410
1411 assert (ifc != NULL);
1412
paul931cd542004-01-23 15:31:42 +00001413 if (IS_RIP_DEBUG_PACKET)
1414 {
paulf69bd9d2005-06-03 18:01:50 +00001415#define ADDRESS_SIZE 20
1416 char dst[ADDRESS_SIZE];
1417 dst[ADDRESS_SIZE - 1] = '\0';
1418
paul931cd542004-01-23 15:31:42 +00001419 if (to)
1420 {
paulf69bd9d2005-06-03 18:01:50 +00001421 strncpy (dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001422 }
1423 else
1424 {
1425 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paulf69bd9d2005-06-03 18:01:50 +00001426 strncpy (dst, inet_ntoa(sin.sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001427 }
paulf69bd9d2005-06-03 18:01:50 +00001428#undef ADDRESS_SIZE
ajs5d6c3772004-12-08 19:24:06 +00001429 zlog_debug("rip_send_packet %s > %s (%s)",
paulc49ad8f2004-10-22 10:27:28 +00001430 inet_ntoa(ifc->address->u.prefix4),
1431 dst, ifc->ifp->name);
paul931cd542004-01-23 15:31:42 +00001432 }
paulf69bd9d2005-06-03 18:01:50 +00001433
paulc49ad8f2004-10-22 10:27:28 +00001434 if ( CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY) )
paul931cd542004-01-23 15:31:42 +00001435 {
1436 /*
1437 * ZEBRA_IFA_SECONDARY is set on linux when an interface is configured
1438 * with multiple addresses on the same subnet: the first address
1439 * on the subnet is configured "primary", and all subsequent addresses
1440 * on that subnet are treated as "secondary" addresses.
1441 * In order to avoid routing-table bloat on other rip listeners,
1442 * we do not send out RIP packets with ZEBRA_IFA_SECONDARY source addrs.
1443 * XXX Since Linux is the only system for which the ZEBRA_IFA_SECONDARY
1444 * flag is set, we would end up sending a packet for a "secondary"
1445 * source address on non-linux systems.
1446 */
1447 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001448 zlog_debug("duplicate dropped");
paul931cd542004-01-23 15:31:42 +00001449 return 0;
1450 }
1451
paul718e3742002-12-13 20:15:29 +00001452 /* Make destination address. */
1453 memset (&sin, 0, sizeof (struct sockaddr_in));
1454 sin.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001455#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +00001456 sin.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001457#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +00001458
1459 /* When destination is specified, use it's port and address. */
1460 if (to)
1461 {
paul718e3742002-12-13 20:15:29 +00001462 sin.sin_port = to->sin_port;
1463 sin.sin_addr = to->sin_addr;
paul931cd542004-01-23 15:31:42 +00001464 send_sock = rip->sock;
paul718e3742002-12-13 20:15:29 +00001465 }
1466 else
1467 {
paul2c61ae32005-08-16 15:22:14 +00001468 struct sockaddr_in from;
1469
paul718e3742002-12-13 20:15:29 +00001470 sin.sin_port = htons (RIP_PORT_DEFAULT);
1471 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paul2c61ae32005-08-16 15:22:14 +00001472
1473 /* multicast send should bind to local interface address */
Nick Hilliardbb2315f2012-08-18 15:10:57 +00001474 memset (&from, 0, sizeof (from));
paul2c61ae32005-08-16 15:22:14 +00001475 from.sin_family = AF_INET;
1476 from.sin_port = htons (RIP_PORT_DEFAULT);
1477 from.sin_addr = ifc->address->u.prefix4;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001478#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001479 from.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001480#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul2c61ae32005-08-16 15:22:14 +00001481
paul931cd542004-01-23 15:31:42 +00001482 /*
1483 * we have to open a new socket for each packet because this
1484 * is the most portable way to bind to a different source
1485 * ipv4 address for each packet.
1486 */
paul2c61ae32005-08-16 15:22:14 +00001487 if ( (send_sock = rip_create_socket (&from)) < 0)
paul931cd542004-01-23 15:31:42 +00001488 {
paulf69bd9d2005-06-03 18:01:50 +00001489 zlog_warn("rip_send_packet could not create socket.");
paul931cd542004-01-23 15:31:42 +00001490 return -1;
paulf69bd9d2005-06-03 18:01:50 +00001491 }
paulc49ad8f2004-10-22 10:27:28 +00001492 rip_interface_multicast_set (send_sock, ifc);
paul718e3742002-12-13 20:15:29 +00001493 }
1494
paul931cd542004-01-23 15:31:42 +00001495 ret = sendto (send_sock, buf, size, 0, (struct sockaddr *)&sin,
paul718e3742002-12-13 20:15:29 +00001496 sizeof (struct sockaddr_in));
1497
1498 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001499 zlog_debug ("SEND to %s.%d", inet_ntoa(sin.sin_addr),
paulcc1131a2003-10-15 23:20:17 +00001500 ntohs (sin.sin_port));
paul718e3742002-12-13 20:15:29 +00001501
1502 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001503 zlog_warn ("can't send packet : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001504
paul931cd542004-01-23 15:31:42 +00001505 if (!to)
1506 close(send_sock);
1507
paul718e3742002-12-13 20:15:29 +00001508 return ret;
1509}
1510
1511/* Add redistributed route to RIP table. */
1512void
1513rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
Paul Jakma9099f9b2016-01-18 10:12:10 +00001514 ifindex_t ifindex, struct in_addr *nexthop,
Christian Franke2bbacea2016-10-01 21:43:17 +02001515 unsigned int metric, unsigned char distance,
1516 route_tag_t tag)
paul718e3742002-12-13 20:15:29 +00001517{
1518 int ret;
Lu Fengb397cf42014-07-18 06:13:18 +00001519 struct route_node *rp = NULL;
1520 struct rip_info *rinfo = NULL, newinfo;
1521 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +00001522
1523 /* Redistribute route */
1524 ret = rip_destination_check (p->prefix);
1525 if (! ret)
1526 return;
1527
1528 rp = route_node_get (rip->table, (struct prefix *) p);
1529
Lu Fengb397cf42014-07-18 06:13:18 +00001530 memset (&newinfo, 0, sizeof (struct rip_info));
1531 newinfo.type = type;
1532 newinfo.sub_type = sub_type;
1533 newinfo.ifindex = ifindex;
1534 newinfo.metric = 1;
1535 newinfo.external_metric = metric;
1536 newinfo.distance = distance;
Christian Franke2bbacea2016-10-01 21:43:17 +02001537 if (tag <= UINT16_MAX) /* RIP only supports 16 bit tags */
1538 newinfo.tag = tag;
Lu Fengb397cf42014-07-18 06:13:18 +00001539 newinfo.rp = rp;
1540 if (nexthop)
1541 newinfo.nexthop = *nexthop;
paul718e3742002-12-13 20:15:29 +00001542
Lu Fengb397cf42014-07-18 06:13:18 +00001543 if ((list = rp->info) != NULL && listcount (list) != 0)
paul718e3742002-12-13 20:15:29 +00001544 {
Lu Fengb397cf42014-07-18 06:13:18 +00001545 rinfo = listgetdata (listhead (list));
1546
paul718e3742002-12-13 20:15:29 +00001547 if (rinfo->type == ZEBRA_ROUTE_CONNECT
1548 && rinfo->sub_type == RIP_ROUTE_INTERFACE
1549 && rinfo->metric != RIP_METRIC_INFINITY)
1550 {
1551 route_unlock_node (rp);
1552 return;
1553 }
1554
1555 /* Manually configured RIP route check. */
1556 if (rinfo->type == ZEBRA_ROUTE_RIP
hasso16705132003-05-25 14:49:19 +00001557 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
1558 (rinfo->sub_type == RIP_ROUTE_DEFAULT)) )
paul718e3742002-12-13 20:15:29 +00001559 {
hasso16705132003-05-25 14:49:19 +00001560 if (type != ZEBRA_ROUTE_RIP || ((sub_type != RIP_ROUTE_STATIC) &&
1561 (sub_type != RIP_ROUTE_DEFAULT)))
paul718e3742002-12-13 20:15:29 +00001562 {
1563 route_unlock_node (rp);
1564 return;
1565 }
1566 }
1567
Lu Fengb397cf42014-07-18 06:13:18 +00001568 rinfo = rip_ecmp_replace (&newinfo);
1569 route_unlock_node (rp);
paul718e3742002-12-13 20:15:29 +00001570 }
Lu Fengb397cf42014-07-18 06:13:18 +00001571 else
1572 rinfo = rip_ecmp_add (&newinfo);
paul718e3742002-12-13 20:15:29 +00001573
hasso16705132003-05-25 14:49:19 +00001574 if (IS_RIP_DEBUG_EVENT) {
1575 if (!nexthop)
ajs5d6c3772004-12-08 19:24:06 +00001576 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso16705132003-05-25 14:49:19 +00001577 inet_ntoa(p->prefix), p->prefixlen,
1578 ifindex2ifname(ifindex));
1579 else
ajs5d6c3772004-12-08 19:24:06 +00001580 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso16705132003-05-25 14:49:19 +00001581 inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop),
1582 ifindex2ifname(ifindex));
1583 }
1584
paul718e3742002-12-13 20:15:29 +00001585 rip_event (RIP_TRIGGERED_UPDATE, 0);
1586}
1587
1588/* Delete redistributed route from RIP table. */
1589void
1590rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,
Paul Jakma9099f9b2016-01-18 10:12:10 +00001591 ifindex_t ifindex)
paul718e3742002-12-13 20:15:29 +00001592{
1593 int ret;
1594 struct route_node *rp;
1595 struct rip_info *rinfo;
1596
1597 ret = rip_destination_check (p->prefix);
1598 if (! ret)
1599 return;
1600
1601 rp = route_node_lookup (rip->table, (struct prefix *) p);
1602 if (rp)
1603 {
Lu Fengb397cf42014-07-18 06:13:18 +00001604 struct list *list = rp->info;
paul718e3742002-12-13 20:15:29 +00001605
Lu Fengb397cf42014-07-18 06:13:18 +00001606 if (list != NULL && listcount (list) != 0)
1607 {
1608 rinfo = listgetdata (listhead (list));
1609 if (rinfo != NULL
1610 && rinfo->type == type
1611 && rinfo->sub_type == sub_type
1612 && rinfo->ifindex == ifindex)
1613 {
1614 /* Perform poisoned reverse. */
1615 rinfo->metric = RIP_METRIC_INFINITY;
1616 RIP_TIMER_ON (rinfo->t_garbage_collect,
1617 rip_garbage_collect, rip->garbage_time);
1618 RIP_TIMER_OFF (rinfo->t_timeout);
1619 rinfo->flags |= RIP_RTF_CHANGED;
paul718e3742002-12-13 20:15:29 +00001620
Lu Fengb397cf42014-07-18 06:13:18 +00001621 if (IS_RIP_DEBUG_EVENT)
1622 zlog_debug ("Poisone %s/%d on the interface %s with an "
1623 "infinity metric [delete]",
1624 inet_ntoa(p->prefix), p->prefixlen,
1625 ifindex2ifname(ifindex));
hasso16705132003-05-25 14:49:19 +00001626
Lu Fengb397cf42014-07-18 06:13:18 +00001627 rip_event (RIP_TRIGGERED_UPDATE, 0);
1628 }
1629 }
1630 route_unlock_node (rp);
paul718e3742002-12-13 20:15:29 +00001631 }
1632}
1633
1634/* Response to request called from rip_read ().*/
pauldc63bfd2005-10-25 23:31:05 +00001635static void
paul718e3742002-12-13 20:15:29 +00001636rip_request_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001637 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001638{
1639 caddr_t lim;
1640 struct rte *rte;
1641 struct prefix_ipv4 p;
1642 struct route_node *rp;
1643 struct rip_info *rinfo;
1644 struct rip_interface *ri;
1645
hasso16705132003-05-25 14:49:19 +00001646 /* Does not reponse to the requests on the loopback interfaces */
paulc49ad8f2004-10-22 10:27:28 +00001647 if (if_is_loopback (ifc->ifp))
hasso16705132003-05-25 14:49:19 +00001648 return;
1649
hasso429a0f82004-02-22 23:42:22 +00001650 /* Check RIP process is enabled on this interface. */
paulc49ad8f2004-10-22 10:27:28 +00001651 ri = ifc->ifp->info;
hasso16705132003-05-25 14:49:19 +00001652 if (! ri->running)
1653 return;
paul718e3742002-12-13 20:15:29 +00001654
1655 /* When passive interface is specified, suppress responses */
1656 if (ri->passive)
1657 return;
paulc49ad8f2004-10-22 10:27:28 +00001658
paul718e3742002-12-13 20:15:29 +00001659 /* RIP peer update. */
1660 rip_peer_update (from, packet->version);
1661
1662 lim = ((caddr_t) packet) + size;
1663 rte = packet->rte;
1664
1665 /* The Request is processed entry by entry. If there are no
1666 entries, no response is given. */
1667 if (lim == (caddr_t) rte)
1668 return;
1669
1670 /* There is one special case. If there is exactly one entry in the
1671 request, and it has an address family identifier of zero and a
1672 metric of infinity (i.e., 16), then this is a request to send the
1673 entire routing table. */
1674 if (lim == ((caddr_t) (rte + 1)) &&
1675 ntohs (rte->family) == 0 &&
1676 ntohl (rte->metric) == RIP_METRIC_INFINITY)
1677 {
1678 /* All route with split horizon */
paulc49ad8f2004-10-22 10:27:28 +00001679 rip_output_process (ifc, from, rip_all_route, packet->version);
paul718e3742002-12-13 20:15:29 +00001680 }
1681 else
1682 {
1683 /* Examine the list of RTEs in the Request one by one. For each
1684 entry, look up the destination in the router's routing
1685 database and, if there is a route, put that route's metric in
1686 the metric field of the RTE. If there is no explicit route
1687 to the specified destination, put infinity in the metric
1688 field. Once all the entries have been filled in, change the
1689 command from Request to Response and send the datagram back
1690 to the requestor. */
1691 p.family = AF_INET;
1692
1693 for (; ((caddr_t) rte) < lim; rte++)
1694 {
1695 p.prefix = rte->prefix;
1696 p.prefixlen = ip_masklen (rte->mask);
1697 apply_mask_ipv4 (&p);
1698
1699 rp = route_node_lookup (rip->table, (struct prefix *) &p);
1700 if (rp)
1701 {
Lu Fengb397cf42014-07-18 06:13:18 +00001702 rinfo = listgetdata (listhead ((struct list *)rp->info));
paul718e3742002-12-13 20:15:29 +00001703 rte->metric = htonl (rinfo->metric);
1704 route_unlock_node (rp);
1705 }
1706 else
1707 rte->metric = htonl (RIP_METRIC_INFINITY);
1708 }
1709 packet->command = RIP_RESPONSE;
1710
paulc49ad8f2004-10-22 10:27:28 +00001711 rip_send_packet ((u_char *)packet, size, from, ifc);
paul718e3742002-12-13 20:15:29 +00001712 }
1713 rip_global_queries++;
1714}
1715
1716#if RIP_RECVMSG
1717/* Set IPv6 packet info to the socket. */
1718static int
1719setsockopt_pktinfo (int sock)
1720{
1721 int ret;
1722 int val = 1;
1723
1724 ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
1725 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001726 zlog_warn ("Can't setsockopt IP_PKTINFO : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001727 return ret;
1728}
1729
1730/* Read RIP packet by recvmsg function. */
1731int
1732rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from,
Paul Jakma9099f9b2016-01-18 10:12:10 +00001733 ifindex_t *ifindex)
paul718e3742002-12-13 20:15:29 +00001734{
1735 int ret;
1736 struct msghdr msg;
1737 struct iovec iov;
1738 struct cmsghdr *ptr;
1739 char adata[1024];
1740
1741 msg.msg_name = (void *) from;
1742 msg.msg_namelen = sizeof (struct sockaddr_in);
1743 msg.msg_iov = &iov;
1744 msg.msg_iovlen = 1;
1745 msg.msg_control = (void *) adata;
1746 msg.msg_controllen = sizeof adata;
1747 iov.iov_base = buf;
1748 iov.iov_len = size;
1749
1750 ret = recvmsg (sock, &msg, 0);
1751 if (ret < 0)
1752 return ret;
1753
ajsb99760a2005-01-04 16:24:43 +00001754 for (ptr = ZCMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr))
paul718e3742002-12-13 20:15:29 +00001755 if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO)
1756 {
1757 struct in_pktinfo *pktinfo;
1758 int i;
1759
1760 pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr);
1761 i = pktinfo->ipi_ifindex;
1762 }
1763 return ret;
1764}
1765
1766/* RIP packet read function. */
1767int
1768rip_read_new (struct thread *t)
1769{
1770 int ret;
1771 int sock;
1772 char buf[RIP_PACKET_MAXSIZ];
1773 struct sockaddr_in from;
Paul Jakma9099f9b2016-01-18 10:12:10 +00001774 ifindex_t ifindex;
paul718e3742002-12-13 20:15:29 +00001775
1776 /* Fetch socket then register myself. */
1777 sock = THREAD_FD (t);
1778 rip_event (RIP_READ, sock);
1779
1780 /* Read RIP packet. */
1781 ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex);
1782 if (ret < 0)
1783 {
ajs6099b3b2004-11-20 02:06:59 +00001784 zlog_warn ("Can't read RIP packet: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001785 return ret;
1786 }
1787
1788 return ret;
1789}
1790#endif /* RIP_RECVMSG */
1791
1792/* First entry point of RIP packet. */
pauldc63bfd2005-10-25 23:31:05 +00001793static int
paul718e3742002-12-13 20:15:29 +00001794rip_read (struct thread *t)
1795{
1796 int sock;
1797 int ret;
1798 int rtenum;
1799 union rip_buf rip_buf;
1800 struct rip_packet *packet;
1801 struct sockaddr_in from;
paul11dde9c2004-05-31 14:00:00 +00001802 int len;
Paul Jakma3e557ae2006-09-11 02:10:40 +00001803 int vrecv;
paul11dde9c2004-05-31 14:00:00 +00001804 socklen_t fromlen;
paul718e3742002-12-13 20:15:29 +00001805 struct interface *ifp;
paulc49ad8f2004-10-22 10:27:28 +00001806 struct connected *ifc;
paul718e3742002-12-13 20:15:29 +00001807 struct rip_interface *ri;
1808
1809 /* Fetch socket then register myself. */
1810 sock = THREAD_FD (t);
1811 rip->t_read = NULL;
1812
1813 /* Add myself to tne next event */
1814 rip_event (RIP_READ, sock);
1815
1816 /* RIPd manages only IPv4. */
1817 memset (&from, 0, sizeof (struct sockaddr_in));
1818 fromlen = sizeof (struct sockaddr_in);
1819
1820 len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0,
1821 (struct sockaddr *) &from, &fromlen);
1822 if (len < 0)
1823 {
ajs6099b3b2004-11-20 02:06:59 +00001824 zlog_info ("recvfrom failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001825 return len;
1826 }
1827
1828 /* Check is this packet comming from myself? */
paul31a476c2003-09-29 19:54:53 +00001829 if (if_check_address (from.sin_addr))
paul718e3742002-12-13 20:15:29 +00001830 {
1831 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001832 zlog_debug ("ignore packet comes from myself");
paul718e3742002-12-13 20:15:29 +00001833 return -1;
1834 }
1835
1836 /* Which interface is this packet comes from. */
1837 ifp = if_lookup_address (from.sin_addr);
paulc49ad8f2004-10-22 10:27:28 +00001838
paul718e3742002-12-13 20:15:29 +00001839 /* RIP packet received */
1840 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001841 zlog_debug ("RECV packet from %s port %d on %s",
paul718e3742002-12-13 20:15:29 +00001842 inet_ntoa (from.sin_addr), ntohs (from.sin_port),
1843 ifp ? ifp->name : "unknown");
1844
1845 /* If this packet come from unknown interface, ignore it. */
1846 if (ifp == NULL)
1847 {
ajs766a0ca2004-12-15 14:55:51 +00001848 zlog_info ("rip_read: cannot find interface for packet from %s port %d",
1849 inet_ntoa(from.sin_addr), ntohs (from.sin_port));
paulc49ad8f2004-10-22 10:27:28 +00001850 return -1;
1851 }
1852
1853 ifc = connected_lookup_address (ifp, from.sin_addr);
1854
1855 if (ifc == NULL)
1856 {
ajs766a0ca2004-12-15 14:55:51 +00001857 zlog_info ("rip_read: cannot find connected address for packet from %s "
1858 "port %d on interface %s",
1859 inet_ntoa(from.sin_addr), ntohs (from.sin_port), ifp->name);
paul718e3742002-12-13 20:15:29 +00001860 return -1;
1861 }
1862
1863 /* Packet length check. */
1864 if (len < RIP_PACKET_MINSIZ)
1865 {
1866 zlog_warn ("packet size %d is smaller than minimum size %d",
1867 len, RIP_PACKET_MINSIZ);
1868 rip_peer_bad_packet (&from);
1869 return len;
1870 }
1871 if (len > RIP_PACKET_MAXSIZ)
1872 {
1873 zlog_warn ("packet size %d is larger than max size %d",
1874 len, RIP_PACKET_MAXSIZ);
1875 rip_peer_bad_packet (&from);
1876 return len;
1877 }
1878
1879 /* Packet alignment check. */
1880 if ((len - RIP_PACKET_MINSIZ) % 20)
1881 {
1882 zlog_warn ("packet size %d is wrong for RIP packet alignment", len);
1883 rip_peer_bad_packet (&from);
1884 return len;
1885 }
1886
1887 /* Set RTE number. */
1888 rtenum = ((len - RIP_PACKET_MINSIZ) / 20);
1889
1890 /* For easy to handle. */
1891 packet = &rip_buf.rip_packet;
1892
1893 /* RIP version check. */
1894 if (packet->version == 0)
1895 {
1896 zlog_info ("version 0 with command %d received.", packet->command);
1897 rip_peer_bad_packet (&from);
1898 return -1;
1899 }
1900
1901 /* Dump RIP packet. */
1902 if (IS_RIP_DEBUG_RECV)
1903 rip_packet_dump (packet, len, "RECV");
1904
1905 /* RIP version adjust. This code should rethink now. RFC1058 says
1906 that "Version 1 implementations are to ignore this extra data and
1907 process only the fields specified in this document.". So RIPv3
1908 packet should be treated as RIPv1 ignoring must be zero field. */
1909 if (packet->version > RIPv2)
1910 packet->version = RIPv2;
1911
1912 /* Is RIP running or is this RIP neighbor ?*/
1913 ri = ifp->info;
1914 if (! ri->running && ! rip_neighbor_lookup (&from))
1915 {
1916 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001917 zlog_debug ("RIP is not enabled on interface %s.", ifp->name);
paul718e3742002-12-13 20:15:29 +00001918 rip_peer_bad_packet (&from);
1919 return -1;
1920 }
1921
Paul Jakma15a2b082006-05-04 07:36:34 +00001922 /* RIP Version check. RFC2453, 4.6 and 5.1 */
Paul Jakma3e557ae2006-09-11 02:10:40 +00001923 vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ?
1924 rip->version_recv : ri->ri_receive);
Paul Jakma15a2b082006-05-04 07:36:34 +00001925 if ((packet->version == RIPv1) && !(vrecv & RIPv1))
paul718e3742002-12-13 20:15:29 +00001926 {
Paul Jakma15a2b082006-05-04 07:36:34 +00001927 if (IS_RIP_DEBUG_PACKET)
1928 zlog_debug (" packet's v%d doesn't fit to if version spec",
1929 packet->version);
1930 rip_peer_bad_packet (&from);
1931 return -1;
paul718e3742002-12-13 20:15:29 +00001932 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001933 if ((packet->version == RIPv2) && !(vrecv & RIPv2))
1934 {
1935 if (IS_RIP_DEBUG_PACKET)
1936 zlog_debug (" packet's v%d doesn't fit to if version spec",
1937 packet->version);
1938 rip_peer_bad_packet (&from);
1939 return -1;
1940 }
1941
paul718e3742002-12-13 20:15:29 +00001942 /* RFC2453 5.2 If the router is not configured to authenticate RIP-2
1943 messages, then RIP-1 and unauthenticated RIP-2 messages will be
1944 accepted; authenticated RIP-2 messages shall be discarded. */
paul718e3742002-12-13 20:15:29 +00001945 if ((ri->auth_type == RIP_NO_AUTH)
1946 && rtenum
paulca5e5162004-06-06 22:06:33 +00001947 && (packet->version == RIPv2)
1948 && (packet->rte->family == htons(RIP_FAMILY_AUTH)))
paul718e3742002-12-13 20:15:29 +00001949 {
1950 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001951 zlog_debug ("packet RIPv%d is dropped because authentication disabled",
paul718e3742002-12-13 20:15:29 +00001952 packet->version);
1953 rip_peer_bad_packet (&from);
1954 return -1;
1955 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001956
1957 /* RFC:
1958 If the router is configured to authenticate RIP-2 messages, then
paul718e3742002-12-13 20:15:29 +00001959 RIP-1 messages and RIP-2 messages which pass authentication
1960 testing shall be accepted; unauthenticated and failed
1961 authentication RIP-2 messages shall be discarded. For maximum
1962 security, RIP-1 messages should be ignored when authentication is
1963 in use (see section 4.1); otherwise, the routing information from
1964 authenticated messages will be propagated by RIP-1 routers in an
Paul Jakma15a2b082006-05-04 07:36:34 +00001965 unauthenticated manner.
1966 */
1967 /* We make an exception for RIPv1 REQUEST packets, to which we'll
1968 * always reply regardless of authentication settings, because:
1969 *
1970 * - if there other authorised routers on-link, the REQUESTor can
1971 * passively obtain the routing updates anyway
1972 * - if there are no other authorised routers on-link, RIP can
1973 * easily be disabled for the link to prevent giving out information
1974 * on state of this routers RIP routing table..
1975 *
1976 * I.e. if RIPv1 has any place anymore these days, it's as a very
1977 * simple way to distribute routing information (e.g. to embedded
1978 * hosts / appliances) and the ability to give out RIPv1
1979 * routing-information freely, while still requiring RIPv2
1980 * authentication for any RESPONSEs might be vaguely useful.
1981 */
1982 if (ri->auth_type != RIP_NO_AUTH
1983 && packet->version == RIPv1)
paul718e3742002-12-13 20:15:29 +00001984 {
Paul Jakma15a2b082006-05-04 07:36:34 +00001985 /* Discard RIPv1 messages other than REQUESTs */
1986 if (packet->command != RIP_REQUEST)
1987 {
1988 if (IS_RIP_DEBUG_PACKET)
1989 zlog_debug ("RIPv1" " dropped because authentication enabled");
1990 rip_peer_bad_packet (&from);
1991 return -1;
1992 }
1993 }
1994 else if (ri->auth_type != RIP_NO_AUTH)
1995 {
1996 const char *auth_desc;
1997
1998 if (rtenum == 0)
1999 {
2000 /* There definitely is no authentication in the packet. */
2001 if (IS_RIP_DEBUG_PACKET)
2002 zlog_debug ("RIPv2 authentication failed: no auth RTE in packet");
2003 rip_peer_bad_packet (&from);
2004 return -1;
2005 }
2006
2007 /* First RTE must be an Authentication Family RTE */
2008 if (packet->rte->family != htons(RIP_FAMILY_AUTH))
2009 {
2010 if (IS_RIP_DEBUG_PACKET)
2011 zlog_debug ("RIPv2" " dropped because authentication enabled");
paul718e3742002-12-13 20:15:29 +00002012 rip_peer_bad_packet (&from);
2013 return -1;
Paul Jakma15a2b082006-05-04 07:36:34 +00002014 }
2015
paul718e3742002-12-13 20:15:29 +00002016 /* Check RIPv2 authentication. */
Paul Jakma15a2b082006-05-04 07:36:34 +00002017 switch (ntohs(packet->rte->tag))
2018 {
2019 case RIP_AUTH_SIMPLE_PASSWORD:
2020 auth_desc = "simple";
2021 ret = rip_auth_simple_password (packet->rte, &from, ifp);
2022 break;
2023
2024 case RIP_AUTH_MD5:
2025 auth_desc = "MD5";
2026 ret = rip_auth_md5 (packet, &from, len, ifp);
2027 /* Reset RIP packet length to trim MD5 data. */
2028 len = ret;
2029 break;
2030
2031 default:
2032 ret = 0;
2033 auth_desc = "unknown type";
2034 if (IS_RIP_DEBUG_PACKET)
2035 zlog_debug ("RIPv2 Unknown authentication type %d",
2036 ntohs (packet->rte->tag));
2037 }
2038
2039 if (ret)
2040 {
2041 if (IS_RIP_DEBUG_PACKET)
2042 zlog_debug ("RIPv2 %s authentication success", auth_desc);
2043 }
2044 else
2045 {
2046 if (IS_RIP_DEBUG_PACKET)
2047 zlog_debug ("RIPv2 %s authentication failure", auth_desc);
2048 rip_peer_bad_packet (&from);
2049 return -1;
2050 }
paul718e3742002-12-13 20:15:29 +00002051 }
2052
2053 /* Process each command. */
2054 switch (packet->command)
2055 {
2056 case RIP_RESPONSE:
paulc49ad8f2004-10-22 10:27:28 +00002057 rip_response_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002058 break;
2059 case RIP_REQUEST:
2060 case RIP_POLL:
paulc49ad8f2004-10-22 10:27:28 +00002061 rip_request_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002062 break;
2063 case RIP_TRACEON:
2064 case RIP_TRACEOFF:
2065 zlog_info ("Obsolete command %s received, please sent it to routed",
2066 lookup (rip_msg, packet->command));
2067 rip_peer_bad_packet (&from);
2068 break;
2069 case RIP_POLL_ENTRY:
2070 zlog_info ("Obsolete command %s received",
2071 lookup (rip_msg, packet->command));
2072 rip_peer_bad_packet (&from);
2073 break;
2074 default:
2075 zlog_info ("Unknown RIP command %d received", packet->command);
2076 rip_peer_bad_packet (&from);
2077 break;
2078 }
2079
2080 return len;
2081}
2082
paul718e3742002-12-13 20:15:29 +00002083/* Write routing table entry to the stream and return next index of
2084 the routing table entry in the stream. */
pauldc63bfd2005-10-25 23:31:05 +00002085static int
paul718e3742002-12-13 20:15:29 +00002086rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p,
paulb14ee002005-02-04 23:42:41 +00002087 u_char version, struct rip_info *rinfo)
paul718e3742002-12-13 20:15:29 +00002088{
2089 struct in_addr mask;
paul718e3742002-12-13 20:15:29 +00002090
2091 /* Write routing table entry. */
2092 if (version == RIPv1)
2093 {
2094 stream_putw (s, AF_INET);
2095 stream_putw (s, 0);
2096 stream_put_ipv4 (s, p->prefix.s_addr);
2097 stream_put_ipv4 (s, 0);
2098 stream_put_ipv4 (s, 0);
2099 stream_putl (s, rinfo->metric_out);
2100 }
2101 else
2102 {
2103 masklen2ip (p->prefixlen, &mask);
2104
2105 stream_putw (s, AF_INET);
hasso16705132003-05-25 14:49:19 +00002106 stream_putw (s, rinfo->tag_out);
paul718e3742002-12-13 20:15:29 +00002107 stream_put_ipv4 (s, p->prefix.s_addr);
2108 stream_put_ipv4 (s, mask.s_addr);
2109 stream_put_ipv4 (s, rinfo->nexthop_out.s_addr);
2110 stream_putl (s, rinfo->metric_out);
2111 }
2112
2113 return ++num;
2114}
2115
2116/* Send update to the ifp or spcified neighbor. */
2117void
paulc49ad8f2004-10-22 10:27:28 +00002118rip_output_process (struct connected *ifc, struct sockaddr_in *to,
2119 int route_type, u_char version)
paul718e3742002-12-13 20:15:29 +00002120{
2121 int ret;
2122 struct stream *s;
2123 struct route_node *rp;
2124 struct rip_info *rinfo;
2125 struct rip_interface *ri;
2126 struct prefix_ipv4 *p;
2127 struct prefix_ipv4 classfull;
paul727d1042002-12-13 20:50:29 +00002128 struct prefix_ipv4 ifaddrclass;
paulb14ee002005-02-04 23:42:41 +00002129 struct key *key = NULL;
2130 /* this might need to made dynamic if RIP ever supported auth methods
2131 with larger key string sizes */
2132 char auth_str[RIP_AUTH_SIMPLE_SIZE];
pauldc63bfd2005-10-25 23:31:05 +00002133 size_t doff = 0; /* offset of digest offset field */
paul2c61ae32005-08-16 15:22:14 +00002134 int num = 0;
paul718e3742002-12-13 20:15:29 +00002135 int rtemax;
paul01d09082003-06-08 21:22:18 +00002136 int subnetted = 0;
Lu Fengb397cf42014-07-18 06:13:18 +00002137 struct list *list = NULL;
2138 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00002139
2140 /* Logging output event. */
2141 if (IS_RIP_DEBUG_EVENT)
2142 {
2143 if (to)
ajs5d6c3772004-12-08 19:24:06 +00002144 zlog_debug ("update routes to neighbor %s", inet_ntoa (to->sin_addr));
paul718e3742002-12-13 20:15:29 +00002145 else
ajs5d6c3772004-12-08 19:24:06 +00002146 zlog_debug ("update routes on interface %s ifindex %d",
paulc49ad8f2004-10-22 10:27:28 +00002147 ifc->ifp->name, ifc->ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002148 }
2149
2150 /* Set output stream. */
2151 s = rip->obuf;
2152
2153 /* Reset stream and RTE counter. */
2154 stream_reset (s);
Lu Feng342a31b2014-06-25 07:43:15 +00002155 rtemax = RIP_MAX_RTE;
paul718e3742002-12-13 20:15:29 +00002156
2157 /* Get RIP interface. */
paulc49ad8f2004-10-22 10:27:28 +00002158 ri = ifc->ifp->info;
paul718e3742002-12-13 20:15:29 +00002159
2160 /* If output interface is in simple password authentication mode, we
2161 need space for authentication data. */
2162 if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
2163 rtemax -= 1;
2164
2165 /* If output interface is in MD5 authentication mode, we need space
2166 for authentication header and data. */
2167 if (ri->auth_type == RIP_AUTH_MD5)
2168 rtemax -= 2;
2169
2170 /* If output interface is in simple password authentication mode
2171 and string or keychain is specified we need space for auth. data */
paulb14ee002005-02-04 23:42:41 +00002172 if (ri->auth_type != RIP_NO_AUTH)
paul718e3742002-12-13 20:15:29 +00002173 {
2174 if (ri->key_chain)
2175 {
2176 struct keychain *keychain;
2177
2178 keychain = keychain_lookup (ri->key_chain);
2179 if (keychain)
paulb14ee002005-02-04 23:42:41 +00002180 key = key_lookup_for_send (keychain);
paul718e3742002-12-13 20:15:29 +00002181 }
paulb14ee002005-02-04 23:42:41 +00002182 /* to be passed to auth functions later */
2183 rip_auth_prepare_str_send (ri, key, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002184 }
2185
paul727d1042002-12-13 20:50:29 +00002186 if (version == RIPv1)
2187 {
paulc49ad8f2004-10-22 10:27:28 +00002188 memcpy (&ifaddrclass, ifc->address, sizeof (struct prefix_ipv4));
paul727d1042002-12-13 20:50:29 +00002189 apply_classful_mask_ipv4 (&ifaddrclass);
2190 subnetted = 0;
paulc49ad8f2004-10-22 10:27:28 +00002191 if (ifc->address->prefixlen > ifaddrclass.prefixlen)
paul01d09082003-06-08 21:22:18 +00002192 subnetted = 1;
paul727d1042002-12-13 20:50:29 +00002193 }
2194
paul718e3742002-12-13 20:15:29 +00002195 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002196 if ((list = rp->info) != NULL && listcount (list) != 0)
paul718e3742002-12-13 20:15:29 +00002197 {
Lu Fengb397cf42014-07-18 06:13:18 +00002198 rinfo = listgetdata (listhead (list));
paul727d1042002-12-13 20:50:29 +00002199 /* For RIPv1, if we are subnetted, output subnets in our network */
2200 /* that have the same mask as the output "interface". For other */
2201 /* networks, only the classfull version is output. */
paul718e3742002-12-13 20:15:29 +00002202
2203 if (version == RIPv1)
2204 {
paul727d1042002-12-13 20:50:29 +00002205 p = (struct prefix_ipv4 *) &rp->p;
paul718e3742002-12-13 20:15:29 +00002206
2207 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002208 zlog_debug("RIPv1 mask check, %s/%d considered for output",
paul727d1042002-12-13 20:50:29 +00002209 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002210
paul727d1042002-12-13 20:50:29 +00002211 if (subnetted &&
2212 prefix_match ((struct prefix *) &ifaddrclass, &rp->p))
2213 {
paulc49ad8f2004-10-22 10:27:28 +00002214 if ((ifc->address->prefixlen != rp->p.prefixlen) &&
paul727d1042002-12-13 20:50:29 +00002215 (rp->p.prefixlen != 32))
2216 continue;
2217 }
2218 else
2219 {
2220 memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4));
2221 apply_classful_mask_ipv4(&classfull);
2222 if (rp->p.u.prefix4.s_addr != 0 &&
2223 classfull.prefixlen != rp->p.prefixlen)
2224 continue;
2225 }
paul718e3742002-12-13 20:15:29 +00002226 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002227 zlog_debug("RIPv1 mask check, %s/%d made it through",
paul727d1042002-12-13 20:50:29 +00002228 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002229 }
2230 else
2231 p = (struct prefix_ipv4 *) &rp->p;
2232
2233 /* Apply output filters. */
Matthieu Boutierfafa8992014-09-10 16:50:43 +02002234 ret = rip_filter (RIP_FILTER_OUT, p, ri);
paul718e3742002-12-13 20:15:29 +00002235 if (ret < 0)
2236 continue;
2237
2238 /* Changed route only output. */
2239 if (route_type == rip_changed_route &&
2240 (! (rinfo->flags & RIP_RTF_CHANGED)))
2241 continue;
2242
2243 /* Split horizon. */
2244 /* if (split_horizon == rip_split_horizon) */
hasso16705132003-05-25 14:49:19 +00002245 if (ri->split_horizon == RIP_SPLIT_HORIZON)
paul718e3742002-12-13 20:15:29 +00002246 {
paul42d14d92003-11-17 09:15:18 +00002247 /*
2248 * We perform split horizon for RIP and connected route.
2249 * For rip routes, we want to suppress the route if we would
2250 * end up sending the route back on the interface that we
2251 * learned it from, with a higher metric. For connected routes,
2252 * we suppress the route if the prefix is a subset of the
2253 * source address that we are going to use for the packet
2254 * (in order to handle the case when multiple subnets are
2255 * configured on the same interface).
2256 */
Lu Fengb397cf42014-07-18 06:13:18 +00002257 int suppress = 0;
2258 struct rip_info *tmp_rinfo = NULL;
2259
2260 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
2261 if (tmp_rinfo->type == ZEBRA_ROUTE_RIP &&
2262 tmp_rinfo->ifindex == ifc->ifp->ifindex)
2263 {
2264 suppress = 1;
2265 break;
2266 }
2267
2268 if (!suppress && rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002269 prefix_match((struct prefix *)p, ifc->address))
Lu Fengb397cf42014-07-18 06:13:18 +00002270 suppress = 1;
2271
2272 if (suppress)
paul718e3742002-12-13 20:15:29 +00002273 continue;
2274 }
2275
2276 /* Preparation for route-map. */
2277 rinfo->metric_set = 0;
2278 rinfo->nexthop_out.s_addr = 0;
2279 rinfo->metric_out = rinfo->metric;
hasso16705132003-05-25 14:49:19 +00002280 rinfo->tag_out = rinfo->tag;
paulc49ad8f2004-10-22 10:27:28 +00002281 rinfo->ifindex_out = ifc->ifp->ifindex;
paul718e3742002-12-13 20:15:29 +00002282
hasso16705132003-05-25 14:49:19 +00002283 /* In order to avoid some local loops,
2284 * if the RIP route has a nexthop via this interface, keep the nexthop,
2285 * otherwise set it to 0. The nexthop should not be propagated
2286 * beyond the local broadcast/multicast area in order
2287 * to avoid an IGP multi-level recursive look-up.
2288 * see (4.4)
2289 */
paulc49ad8f2004-10-22 10:27:28 +00002290 if (rinfo->ifindex == ifc->ifp->ifindex)
paul718e3742002-12-13 20:15:29 +00002291 rinfo->nexthop_out = rinfo->nexthop;
hasso16705132003-05-25 14:49:19 +00002292
2293 /* Interface route-map */
2294 if (ri->routemap[RIP_FILTER_OUT])
2295 {
2296 ret = route_map_apply (ri->routemap[RIP_FILTER_OUT],
2297 (struct prefix *) p, RMAP_RIP,
2298 rinfo);
2299
2300 if (ret == RMAP_DENYMATCH)
2301 {
2302 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002303 zlog_debug ("RIP %s/%d is filtered by route-map out",
hasso16705132003-05-25 14:49:19 +00002304 inet_ntoa (p->prefix), p->prefixlen);
Paul Jakmab174a582017-01-23 10:55:26 +00002305 continue;
hasso16705132003-05-25 14:49:19 +00002306 }
2307 }
paul718e3742002-12-13 20:15:29 +00002308
hasso16705132003-05-25 14:49:19 +00002309 /* Apply redistribute route map - continue, if deny */
paul718e3742002-12-13 20:15:29 +00002310 if (rip->route_map[rinfo->type].name
2311 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2312 {
2313 ret = route_map_apply (rip->route_map[rinfo->type].map,
2314 (struct prefix *)p, RMAP_RIP, rinfo);
2315
2316 if (ret == RMAP_DENYMATCH)
2317 {
2318 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002319 zlog_debug ("%s/%d is filtered by route-map",
paul718e3742002-12-13 20:15:29 +00002320 inet_ntoa (p->prefix), p->prefixlen);
2321 continue;
2322 }
2323 }
2324
2325 /* When route-map does not set metric. */
2326 if (! rinfo->metric_set)
2327 {
2328 /* If redistribute metric is set. */
2329 if (rip->route_map[rinfo->type].metric_config
2330 && rinfo->metric != RIP_METRIC_INFINITY)
2331 {
2332 rinfo->metric_out = rip->route_map[rinfo->type].metric;
2333 }
2334 else
2335 {
2336 /* If the route is not connected or localy generated
2337 one, use default-metric value*/
2338 if (rinfo->type != ZEBRA_ROUTE_RIP
2339 && rinfo->type != ZEBRA_ROUTE_CONNECT
2340 && rinfo->metric != RIP_METRIC_INFINITY)
2341 rinfo->metric_out = rip->default_metric;
2342 }
2343 }
2344
2345 /* Apply offset-list */
2346 if (rinfo->metric != RIP_METRIC_INFINITY)
paulc49ad8f2004-10-22 10:27:28 +00002347 rip_offset_list_apply_out (p, ifc->ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00002348
2349 if (rinfo->metric_out > RIP_METRIC_INFINITY)
2350 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002351
2352 /* Perform split-horizon with poisoned reverse
2353 * for RIP and connected routes.
2354 **/
2355 if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) {
paul42d14d92003-11-17 09:15:18 +00002356 /*
2357 * We perform split horizon for RIP and connected route.
2358 * For rip routes, we want to suppress the route if we would
2359 * end up sending the route back on the interface that we
2360 * learned it from, with a higher metric. For connected routes,
2361 * we suppress the route if the prefix is a subset of the
2362 * source address that we are going to use for the packet
2363 * (in order to handle the case when multiple subnets are
2364 * configured on the same interface).
2365 */
Lu Fengb397cf42014-07-18 06:13:18 +00002366 struct rip_info *tmp_rinfo = NULL;
2367
2368 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
Donald Sharp7e7a1012016-04-08 22:03:22 -04002369 {
2370 if (tmp_rinfo->type == ZEBRA_ROUTE_RIP &&
2371 tmp_rinfo->ifindex == ifc->ifp->ifindex)
2372 rinfo->metric_out = RIP_METRIC_INFINITY;
2373 if (tmp_rinfo->type == ZEBRA_ROUTE_CONNECT &&
2374 prefix_match((struct prefix *)p, ifc->address))
2375 rinfo->metric_out = RIP_METRIC_INFINITY;
2376 }
hasso16705132003-05-25 14:49:19 +00002377 }
paulb14ee002005-02-04 23:42:41 +00002378
2379 /* Prepare preamble, auth headers, if needs be */
2380 if (num == 0)
2381 {
2382 stream_putc (s, RIP_RESPONSE);
2383 stream_putc (s, version);
2384 stream_putw (s, 0);
2385
paul0cb8a012005-05-29 11:27:24 +00002386 /* auth header for !v1 && !no_auth */
2387 if ( (ri->auth_type != RIP_NO_AUTH) && (version != RIPv1) )
paulb14ee002005-02-04 23:42:41 +00002388 doff = rip_auth_header_write (s, ri, key, auth_str,
2389 RIP_AUTH_SIMPLE_SIZE);
2390 }
2391
paul718e3742002-12-13 20:15:29 +00002392 /* Write RTE to the stream. */
paulb14ee002005-02-04 23:42:41 +00002393 num = rip_write_rte (num, s, p, version, rinfo);
paul718e3742002-12-13 20:15:29 +00002394 if (num == rtemax)
2395 {
2396 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002397 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002398
2399 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s),
paulc49ad8f2004-10-22 10:27:28 +00002400 to, ifc);
paul718e3742002-12-13 20:15:29 +00002401
2402 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2403 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2404 stream_get_endp(s), "SEND");
2405 num = 0;
2406 stream_reset (s);
2407 }
2408 }
2409
2410 /* Flush unwritten RTE. */
2411 if (num != 0)
2412 {
2413 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002414 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002415
paulc49ad8f2004-10-22 10:27:28 +00002416 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifc);
paul718e3742002-12-13 20:15:29 +00002417
2418 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2419 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2420 stream_get_endp (s), "SEND");
2421 num = 0;
2422 stream_reset (s);
2423 }
2424
2425 /* Statistics updates. */
2426 ri->sent_updates++;
2427}
2428
2429/* Send RIP packet to the interface. */
pauldc63bfd2005-10-25 23:31:05 +00002430static void
paulc49ad8f2004-10-22 10:27:28 +00002431rip_update_interface (struct connected *ifc, u_char version, int route_type)
paul718e3742002-12-13 20:15:29 +00002432{
paul718e3742002-12-13 20:15:29 +00002433 struct sockaddr_in to;
2434
2435 /* When RIP version is 2 and multicast enable interface. */
paulc49ad8f2004-10-22 10:27:28 +00002436 if (version == RIPv2 && if_is_multicast (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002437 {
2438 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002439 zlog_debug ("multicast announce on %s ", ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002440
paulc49ad8f2004-10-22 10:27:28 +00002441 rip_output_process (ifc, NULL, route_type, version);
paul718e3742002-12-13 20:15:29 +00002442 return;
2443 }
paulc49ad8f2004-10-22 10:27:28 +00002444
paul718e3742002-12-13 20:15:29 +00002445 /* If we can't send multicast packet, send it with unicast. */
paulc49ad8f2004-10-22 10:27:28 +00002446 if (if_is_broadcast (ifc->ifp) || if_is_pointopoint (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002447 {
paulc49ad8f2004-10-22 10:27:28 +00002448 if (ifc->address->family == AF_INET)
2449 {
2450 /* Destination address and port setting. */
2451 memset (&to, 0, sizeof (struct sockaddr_in));
2452 if (ifc->destination)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002453 /* use specified broadcast or peer destination addr */
paulc49ad8f2004-10-22 10:27:28 +00002454 to.sin_addr = ifc->destination->u.prefix4;
Andrew J. Schorre4529632006-12-12 19:18:21 +00002455 else if (ifc->address->prefixlen < IPV4_MAX_PREFIXLEN)
paulc49ad8f2004-10-22 10:27:28 +00002456 /* calculate the appropriate broadcast address */
2457 to.sin_addr.s_addr =
2458 ipv4_broadcast_addr(ifc->address->u.prefix4.s_addr,
2459 ifc->address->prefixlen);
Andrew J. Schorre4529632006-12-12 19:18:21 +00002460 else
2461 /* do not know where to send the packet */
2462 return;
paulc49ad8f2004-10-22 10:27:28 +00002463 to.sin_port = htons (RIP_PORT_DEFAULT);
paul718e3742002-12-13 20:15:29 +00002464
paulc49ad8f2004-10-22 10:27:28 +00002465 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002466 zlog_debug("%s announce to %s on %s",
2467 CONNECTED_PEER(ifc) ? "unicast" : "broadcast",
2468 inet_ntoa (to.sin_addr), ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002469
paulc49ad8f2004-10-22 10:27:28 +00002470 rip_output_process (ifc, &to, route_type, version);
2471 }
paul718e3742002-12-13 20:15:29 +00002472 }
2473}
2474
2475/* Update send to all interface and neighbor. */
pauldc63bfd2005-10-25 23:31:05 +00002476static void
paul718e3742002-12-13 20:15:29 +00002477rip_update_process (int route_type)
2478{
paul1eb8ef22005-04-07 07:30:20 +00002479 struct listnode *node;
2480 struct listnode *ifnode, *ifnnode;
paulcc1131a2003-10-15 23:20:17 +00002481 struct connected *connected;
paul718e3742002-12-13 20:15:29 +00002482 struct interface *ifp;
2483 struct rip_interface *ri;
2484 struct route_node *rp;
2485 struct sockaddr_in to;
2486 struct prefix_ipv4 *p;
2487
2488 /* Send RIP update to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00002489 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00002490 {
paul718e3742002-12-13 20:15:29 +00002491 if (if_is_loopback (ifp))
2492 continue;
2493
paul2e3b2e42002-12-13 21:03:13 +00002494 if (! if_is_operative (ifp))
paul718e3742002-12-13 20:15:29 +00002495 continue;
2496
2497 /* Fetch RIP interface information. */
2498 ri = ifp->info;
2499
2500 /* When passive interface is specified, suppress announce to the
2501 interface. */
2502 if (ri->passive)
2503 continue;
2504
2505 if (ri->running)
2506 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002507 /*
2508 * If there is no version configuration in the interface,
2509 * use rip's version setting.
2510 */
2511 int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
2512 rip->version_send : ri->ri_send);
2513
paul718e3742002-12-13 20:15:29 +00002514 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002515 zlog_debug("SEND UPDATE to %s ifindex %d",
Christian Franke1ca8d402015-11-10 17:45:03 +01002516 ifp->name, ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002517
paulcc1131a2003-10-15 23:20:17 +00002518 /* send update on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002519 for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002520 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002521 if (connected->address->family == AF_INET)
2522 {
2523 if (vsend & RIPv1)
2524 rip_update_interface (connected, RIPv1, route_type);
2525 if ((vsend & RIPv2) && if_is_multicast(ifp))
2526 rip_update_interface (connected, RIPv2, route_type);
2527 }
2528 }
paul718e3742002-12-13 20:15:29 +00002529 }
2530 }
2531
2532 /* RIP send updates to each neighbor. */
2533 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
2534 if (rp->info != NULL)
2535 {
2536 p = (struct prefix_ipv4 *) &rp->p;
2537
2538 ifp = if_lookup_address (p->prefix);
2539 if (! ifp)
2540 {
paulc49ad8f2004-10-22 10:27:28 +00002541 zlog_warn ("Neighbor %s doesnt have connected interface!",
paul718e3742002-12-13 20:15:29 +00002542 inet_ntoa (p->prefix));
2543 continue;
2544 }
paulc49ad8f2004-10-22 10:27:28 +00002545
2546 if ( (connected = connected_lookup_address (ifp, p->prefix)) == NULL)
2547 {
2548 zlog_warn ("Neighbor %s doesnt have connected network",
2549 inet_ntoa (p->prefix));
2550 continue;
2551 }
2552
paul718e3742002-12-13 20:15:29 +00002553 /* Set destination address and port */
2554 memset (&to, 0, sizeof (struct sockaddr_in));
2555 to.sin_addr = p->prefix;
2556 to.sin_port = htons (RIP_PORT_DEFAULT);
2557
2558 /* RIP version is rip's configuration. */
paulc49ad8f2004-10-22 10:27:28 +00002559 rip_output_process (connected, &to, route_type, rip->version_send);
paul718e3742002-12-13 20:15:29 +00002560 }
2561}
2562
2563/* RIP's periodical timer. */
pauldc63bfd2005-10-25 23:31:05 +00002564static int
paul718e3742002-12-13 20:15:29 +00002565rip_update (struct thread *t)
2566{
2567 /* Clear timer pointer. */
2568 rip->t_update = NULL;
2569
2570 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002571 zlog_debug ("update timer fire!");
paul718e3742002-12-13 20:15:29 +00002572
2573 /* Process update output. */
2574 rip_update_process (rip_all_route);
2575
2576 /* Triggered updates may be suppressed if a regular update is due by
2577 the time the triggered update would be sent. */
2578 if (rip->t_triggered_interval)
2579 {
2580 thread_cancel (rip->t_triggered_interval);
2581 rip->t_triggered_interval = NULL;
2582 }
2583 rip->trigger = 0;
2584
2585 /* Register myself. */
2586 rip_event (RIP_UPDATE_EVENT, 0);
2587
2588 return 0;
2589}
2590
2591/* Walk down the RIP routing table then clear changed flag. */
pauldc63bfd2005-10-25 23:31:05 +00002592static void
paul216565a2005-10-25 23:35:28 +00002593rip_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00002594{
2595 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00002596 struct rip_info *rinfo = NULL;
2597 struct list *list = NULL;
2598 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00002599
2600 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002601 if ((list = rp->info) != NULL)
2602 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
2603 {
2604 UNSET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
2605 /* This flag can be set only on the first entry. */
2606 break;
2607 }
paul718e3742002-12-13 20:15:29 +00002608}
2609
2610/* Triggered update interval timer. */
pauldc63bfd2005-10-25 23:31:05 +00002611static int
paul718e3742002-12-13 20:15:29 +00002612rip_triggered_interval (struct thread *t)
2613{
2614 int rip_triggered_update (struct thread *);
2615
2616 rip->t_triggered_interval = NULL;
2617
2618 if (rip->trigger)
2619 {
2620 rip->trigger = 0;
2621 rip_triggered_update (t);
2622 }
2623 return 0;
2624}
2625
2626/* Execute triggered update. */
pauldc63bfd2005-10-25 23:31:05 +00002627static int
paul718e3742002-12-13 20:15:29 +00002628rip_triggered_update (struct thread *t)
2629{
2630 int interval;
2631
2632 /* Clear thred pointer. */
2633 rip->t_triggered_update = NULL;
2634
2635 /* Cancel interval timer. */
2636 if (rip->t_triggered_interval)
2637 {
2638 thread_cancel (rip->t_triggered_interval);
2639 rip->t_triggered_interval = NULL;
2640 }
2641 rip->trigger = 0;
2642
2643 /* Logging triggered update. */
2644 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002645 zlog_debug ("triggered update!");
paul718e3742002-12-13 20:15:29 +00002646
2647 /* Split Horizon processing is done when generating triggered
2648 updates as well as normal updates (see section 2.6). */
2649 rip_update_process (rip_changed_route);
2650
2651 /* Once all of the triggered updates have been generated, the route
2652 change flags should be cleared. */
2653 rip_clear_changed_flag ();
2654
2655 /* After a triggered update is sent, a timer should be set for a
2656 random interval between 1 and 5 seconds. If other changes that
2657 would trigger updates occur before the timer expires, a single
2658 update is triggered when the timer expires. */
2659 interval = (random () % 5) + 1;
2660
2661 rip->t_triggered_interval =
2662 thread_add_timer (master, rip_triggered_interval, NULL, interval);
2663
2664 return 0;
2665}
2666
2667/* Withdraw redistributed route. */
2668void
2669rip_redistribute_withdraw (int type)
2670{
2671 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00002672 struct rip_info *rinfo = NULL;
2673 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +00002674
2675 if (!rip)
2676 return;
2677
2678 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002679 if ((list = rp->info) != NULL)
paul718e3742002-12-13 20:15:29 +00002680 {
Lu Fengb397cf42014-07-18 06:13:18 +00002681 rinfo = listgetdata (listhead (list));
paul718e3742002-12-13 20:15:29 +00002682 if (rinfo->type == type
2683 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2684 {
2685 /* Perform poisoned reverse. */
2686 rinfo->metric = RIP_METRIC_INFINITY;
2687 RIP_TIMER_ON (rinfo->t_garbage_collect,
2688 rip_garbage_collect, rip->garbage_time);
2689 RIP_TIMER_OFF (rinfo->t_timeout);
2690 rinfo->flags |= RIP_RTF_CHANGED;
2691
hasso16705132003-05-25 14:49:19 +00002692 if (IS_RIP_DEBUG_EVENT) {
2693 struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p;
2694
ajs5d6c3772004-12-08 19:24:06 +00002695 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]",
hasso16705132003-05-25 14:49:19 +00002696 inet_ntoa(p->prefix), p->prefixlen,
2697 ifindex2ifname(rinfo->ifindex));
2698 }
2699
paul718e3742002-12-13 20:15:29 +00002700 rip_event (RIP_TRIGGERED_UPDATE, 0);
2701 }
2702 }
2703}
2704
2705/* Create new RIP instance and set it to global variable. */
pauldc63bfd2005-10-25 23:31:05 +00002706static int
2707rip_create (void)
paul718e3742002-12-13 20:15:29 +00002708{
Stephen Hemminger393deb92008-08-18 14:13:29 -07002709 rip = XCALLOC (MTYPE_RIP, sizeof (struct rip));
paul718e3742002-12-13 20:15:29 +00002710
2711 /* Set initial value. */
paulf38a4712003-06-07 01:10:00 +00002712 rip->version_send = RI_RIP_VERSION_2;
2713 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002714 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
2715 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
2716 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
2717 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
2718
2719 /* Initialize RIP routig table. */
2720 rip->table = route_table_init ();
2721 rip->route = route_table_init ();
2722 rip->neighbor = route_table_init ();
2723
2724 /* Make output stream. */
2725 rip->obuf = stream_new (1500);
2726
2727 /* Make socket. */
paulf69bd9d2005-06-03 18:01:50 +00002728 rip->sock = rip_create_socket (NULL);
paul718e3742002-12-13 20:15:29 +00002729 if (rip->sock < 0)
2730 return rip->sock;
2731
2732 /* Create read and timer thread. */
2733 rip_event (RIP_READ, rip->sock);
2734 rip_event (RIP_UPDATE_EVENT, 1);
2735
2736 return 0;
2737}
2738
2739/* Sned RIP request to the destination. */
2740int
2741rip_request_send (struct sockaddr_in *to, struct interface *ifp,
paul931cd542004-01-23 15:31:42 +00002742 u_char version, struct connected *connected)
paul718e3742002-12-13 20:15:29 +00002743{
2744 struct rte *rte;
2745 struct rip_packet rip_packet;
paul1eb8ef22005-04-07 07:30:20 +00002746 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00002747
2748 memset (&rip_packet, 0, sizeof (rip_packet));
2749
2750 rip_packet.command = RIP_REQUEST;
2751 rip_packet.version = version;
2752 rte = rip_packet.rte;
2753 rte->metric = htonl (RIP_METRIC_INFINITY);
2754
paul931cd542004-01-23 15:31:42 +00002755 if (connected)
2756 {
2757 /*
2758 * connected is only sent for ripv1 case, or when
2759 * interface does not support multicast. Caller loops
2760 * over each connected address for this case.
2761 */
paul11dde9c2004-05-31 14:00:00 +00002762 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002763 to, connected) != sizeof (rip_packet))
paul931cd542004-01-23 15:31:42 +00002764 return -1;
2765 else
2766 return sizeof (rip_packet);
2767 }
2768
paulcc1131a2003-10-15 23:20:17 +00002769 /* send request on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002770 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002771 {
2772 struct prefix_ipv4 *p;
2773
2774 p = (struct prefix_ipv4 *) connected->address;
2775
2776 if (p->family != AF_INET)
2777 continue;
2778
paul11dde9c2004-05-31 14:00:00 +00002779 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002780 to, connected) != sizeof (rip_packet))
paulcc1131a2003-10-15 23:20:17 +00002781 return -1;
2782 }
2783 return sizeof (rip_packet);
paul718e3742002-12-13 20:15:29 +00002784}
David Lamparter6b0655a2014-06-04 06:53:35 +02002785
pauldc63bfd2005-10-25 23:31:05 +00002786static int
paul718e3742002-12-13 20:15:29 +00002787rip_update_jitter (unsigned long time)
2788{
paul239389b2004-05-05 14:09:37 +00002789#define JITTER_BOUND 4
2790 /* We want to get the jitter to +/- 1/JITTER_BOUND the interval.
2791 Given that, we cannot let time be less than JITTER_BOUND seconds.
2792 The RIPv2 RFC says jitter should be small compared to
2793 update_time. We consider 1/JITTER_BOUND to be small.
2794 */
2795
2796 int jitter_input = time;
2797 int jitter;
2798
2799 if (jitter_input < JITTER_BOUND)
2800 jitter_input = JITTER_BOUND;
2801
Donald Sharpf31bab42015-06-19 19:26:19 -04002802 jitter = (((random () % ((jitter_input * 2) + 1)) - jitter_input));
paul239389b2004-05-05 14:09:37 +00002803
2804 return jitter/JITTER_BOUND;
paul718e3742002-12-13 20:15:29 +00002805}
2806
2807void
2808rip_event (enum rip_event event, int sock)
2809{
2810 int jitter = 0;
2811
2812 switch (event)
2813 {
2814 case RIP_READ:
2815 rip->t_read = thread_add_read (master, rip_read, NULL, sock);
2816 break;
2817 case RIP_UPDATE_EVENT:
2818 if (rip->t_update)
2819 {
2820 thread_cancel (rip->t_update);
2821 rip->t_update = NULL;
2822 }
2823 jitter = rip_update_jitter (rip->update_time);
2824 rip->t_update =
2825 thread_add_timer (master, rip_update, NULL,
2826 sock ? 2 : rip->update_time + jitter);
2827 break;
2828 case RIP_TRIGGERED_UPDATE:
2829 if (rip->t_triggered_interval)
2830 rip->trigger = 1;
2831 else if (! rip->t_triggered_update)
2832 rip->t_triggered_update =
2833 thread_add_event (master, rip_triggered_update, NULL, 0);
2834 break;
2835 default:
2836 break;
2837 }
2838}
David Lamparter6b0655a2014-06-04 06:53:35 +02002839
paul718e3742002-12-13 20:15:29 +00002840DEFUN (router_rip,
2841 router_rip_cmd,
2842 "router rip",
2843 "Enable a routing process\n"
2844 "Routing Information Protocol (RIP)\n")
2845{
2846 int ret;
2847
2848 /* If rip is not enabled before. */
2849 if (! rip)
2850 {
2851 ret = rip_create ();
2852 if (ret < 0)
2853 {
2854 zlog_info ("Can't create RIP");
2855 return CMD_WARNING;
2856 }
2857 }
2858 vty->node = RIP_NODE;
2859 vty->index = rip;
2860
2861 return CMD_SUCCESS;
2862}
2863
2864DEFUN (no_router_rip,
2865 no_router_rip_cmd,
2866 "no router rip",
2867 NO_STR
2868 "Enable a routing process\n"
2869 "Routing Information Protocol (RIP)\n")
2870{
2871 if (rip)
2872 rip_clean ();
2873 return CMD_SUCCESS;
2874}
2875
2876DEFUN (rip_version,
2877 rip_version_cmd,
2878 "version <1-2>",
2879 "Set routing protocol version\n"
2880 "version\n")
2881{
2882 int version;
2883
2884 version = atoi (argv[0]);
2885 if (version != RIPv1 && version != RIPv2)
2886 {
2887 vty_out (vty, "invalid rip version %d%s", version,
2888 VTY_NEWLINE);
2889 return CMD_WARNING;
2890 }
paulf38a4712003-06-07 01:10:00 +00002891 rip->version_send = version;
2892 rip->version_recv = version;
paul718e3742002-12-13 20:15:29 +00002893
2894 return CMD_SUCCESS;
2895}
2896
2897DEFUN (no_rip_version,
2898 no_rip_version_cmd,
2899 "no version",
2900 NO_STR
2901 "Set routing protocol version\n")
2902{
2903 /* Set RIP version to the default. */
paulf38a4712003-06-07 01:10:00 +00002904 rip->version_send = RI_RIP_VERSION_2;
2905 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002906
2907 return CMD_SUCCESS;
2908}
2909
2910ALIAS (no_rip_version,
2911 no_rip_version_val_cmd,
2912 "no version <1-2>",
2913 NO_STR
2914 "Set routing protocol version\n"
2915 "version\n")
2916
2917DEFUN (rip_route,
2918 rip_route_cmd,
2919 "route A.B.C.D/M",
2920 "RIP static route configuration\n"
2921 "IP prefix <network>/<length>\n")
2922{
2923 int ret;
2924 struct prefix_ipv4 p;
2925 struct route_node *node;
2926
2927 ret = str2prefix_ipv4 (argv[0], &p);
2928 if (ret < 0)
2929 {
2930 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2931 return CMD_WARNING;
2932 }
2933 apply_mask_ipv4 (&p);
2934
2935 /* For router rip configuration. */
2936 node = route_node_get (rip->route, (struct prefix *) &p);
2937
2938 if (node->info)
2939 {
2940 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2941 route_unlock_node (node);
2942 return CMD_WARNING;
2943 }
2944
hasso8a676be2004-10-08 06:36:38 +00002945 node->info = (char *)"static";
paul718e3742002-12-13 20:15:29 +00002946
Christian Franke2bbacea2016-10-01 21:43:17 +02002947 rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0, 0);
paul718e3742002-12-13 20:15:29 +00002948
2949 return CMD_SUCCESS;
2950}
2951
2952DEFUN (no_rip_route,
2953 no_rip_route_cmd,
2954 "no route A.B.C.D/M",
2955 NO_STR
2956 "RIP static route configuration\n"
2957 "IP prefix <network>/<length>\n")
2958{
2959 int ret;
2960 struct prefix_ipv4 p;
2961 struct route_node *node;
2962
2963 ret = str2prefix_ipv4 (argv[0], &p);
2964 if (ret < 0)
2965 {
2966 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2967 return CMD_WARNING;
2968 }
2969 apply_mask_ipv4 (&p);
2970
2971 /* For router rip configuration. */
2972 node = route_node_lookup (rip->route, (struct prefix *) &p);
2973 if (! node)
2974 {
2975 vty_out (vty, "Can't find route %s.%s", argv[0],
2976 VTY_NEWLINE);
2977 return CMD_WARNING;
2978 }
2979
2980 rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
2981 route_unlock_node (node);
2982
2983 node->info = NULL;
2984 route_unlock_node (node);
2985
2986 return CMD_SUCCESS;
2987}
2988
Stephen Hemminger2c239702009-12-10 19:16:05 +03002989#if 0
pauldc63bfd2005-10-25 23:31:05 +00002990static void
paul216565a2005-10-25 23:35:28 +00002991rip_update_default_metric (void)
paul718e3742002-12-13 20:15:29 +00002992{
2993 struct route_node *np;
Lu Fengb397cf42014-07-18 06:13:18 +00002994 struct rip_info *rinfo = NULL;
2995 struct list *list = NULL;
2996 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00002997
2998 for (np = route_top (rip->table); np; np = route_next (np))
Lu Fengb397cf42014-07-18 06:13:18 +00002999 if ((list = np->info) != NULL)
3000 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
3001 if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)
3002 rinfo->metric = rip->default_metric;
paul718e3742002-12-13 20:15:29 +00003003}
Stephen Hemminger2c239702009-12-10 19:16:05 +03003004#endif
paul718e3742002-12-13 20:15:29 +00003005
3006DEFUN (rip_default_metric,
3007 rip_default_metric_cmd,
3008 "default-metric <1-16>",
3009 "Set a metric of redistribute routes\n"
3010 "Default metric\n")
3011{
3012 if (rip)
3013 {
3014 rip->default_metric = atoi (argv[0]);
3015 /* rip_update_default_metric (); */
3016 }
3017 return CMD_SUCCESS;
3018}
3019
3020DEFUN (no_rip_default_metric,
3021 no_rip_default_metric_cmd,
3022 "no default-metric",
3023 NO_STR
3024 "Set a metric of redistribute routes\n"
3025 "Default metric\n")
3026{
3027 if (rip)
3028 {
3029 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
3030 /* rip_update_default_metric (); */
3031 }
3032 return CMD_SUCCESS;
3033}
3034
3035ALIAS (no_rip_default_metric,
3036 no_rip_default_metric_val_cmd,
3037 "no default-metric <1-16>",
3038 NO_STR
3039 "Set a metric of redistribute routes\n"
3040 "Default metric\n")
3041
3042DEFUN (rip_timers,
3043 rip_timers_cmd,
3044 "timers basic <5-2147483647> <5-2147483647> <5-2147483647>",
3045 "Adjust routing timers\n"
3046 "Basic routing protocol update timers\n"
3047 "Routing table update timer value in second. Default is 30.\n"
3048 "Routing information timeout timer. Default is 180.\n"
3049 "Garbage collection timer. Default is 120.\n")
3050{
3051 unsigned long update;
3052 unsigned long timeout;
3053 unsigned long garbage;
3054 char *endptr = NULL;
3055 unsigned long RIP_TIMER_MAX = 2147483647;
3056 unsigned long RIP_TIMER_MIN = 5;
3057
3058 update = strtoul (argv[0], &endptr, 10);
3059 if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')
3060 {
3061 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
3062 return CMD_WARNING;
3063 }
3064
3065 timeout = strtoul (argv[1], &endptr, 10);
3066 if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0')
3067 {
3068 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
3069 return CMD_WARNING;
3070 }
3071
3072 garbage = strtoul (argv[2], &endptr, 10);
3073 if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0')
3074 {
3075 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
3076 return CMD_WARNING;
3077 }
3078
3079 /* Set each timer value. */
3080 rip->update_time = update;
3081 rip->timeout_time = timeout;
3082 rip->garbage_time = garbage;
3083
3084 /* Reset update timer thread. */
3085 rip_event (RIP_UPDATE_EVENT, 0);
3086
3087 return CMD_SUCCESS;
3088}
3089
3090DEFUN (no_rip_timers,
3091 no_rip_timers_cmd,
3092 "no timers basic",
3093 NO_STR
3094 "Adjust routing timers\n"
3095 "Basic routing protocol update timers\n")
3096{
3097 /* Set each timer value to the default. */
3098 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
3099 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
3100 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
3101
3102 /* Reset update timer thread. */
3103 rip_event (RIP_UPDATE_EVENT, 0);
3104
3105 return CMD_SUCCESS;
3106}
hasso16705132003-05-25 14:49:19 +00003107
3108ALIAS (no_rip_timers,
3109 no_rip_timers_val_cmd,
3110 "no timers basic <0-65535> <0-65535> <0-65535>",
3111 NO_STR
3112 "Adjust routing timers\n"
3113 "Basic routing protocol update timers\n"
3114 "Routing table update timer value in second. Default is 30.\n"
3115 "Routing information timeout timer. Default is 180.\n"
3116 "Garbage collection timer. Default is 120.\n")
3117
David Lamparter6b0655a2014-06-04 06:53:35 +02003118
paul718e3742002-12-13 20:15:29 +00003119struct route_table *rip_distance_table;
3120
3121struct rip_distance
3122{
3123 /* Distance value for the IP source prefix. */
3124 u_char distance;
3125
3126 /* Name of the access-list to be matched. */
3127 char *access_list;
3128};
3129
pauldc63bfd2005-10-25 23:31:05 +00003130static struct rip_distance *
paul216565a2005-10-25 23:35:28 +00003131rip_distance_new (void)
paul718e3742002-12-13 20:15:29 +00003132{
Stephen Hemminger393deb92008-08-18 14:13:29 -07003133 return XCALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance));
paul718e3742002-12-13 20:15:29 +00003134}
3135
pauldc63bfd2005-10-25 23:31:05 +00003136static void
paul718e3742002-12-13 20:15:29 +00003137rip_distance_free (struct rip_distance *rdistance)
3138{
3139 XFREE (MTYPE_RIP_DISTANCE, rdistance);
3140}
3141
pauldc63bfd2005-10-25 23:31:05 +00003142static int
hasso98b718a2004-10-11 12:57:57 +00003143rip_distance_set (struct vty *vty, const char *distance_str, const char *ip_str,
3144 const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003145{
3146 int ret;
3147 struct prefix_ipv4 p;
3148 u_char distance;
3149 struct route_node *rn;
3150 struct rip_distance *rdistance;
3151
3152 ret = str2prefix_ipv4 (ip_str, &p);
3153 if (ret == 0)
3154 {
3155 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3156 return CMD_WARNING;
3157 }
3158
3159 distance = atoi (distance_str);
3160
3161 /* Get RIP distance node. */
3162 rn = route_node_get (rip_distance_table, (struct prefix *) &p);
3163 if (rn->info)
3164 {
3165 rdistance = rn->info;
3166 route_unlock_node (rn);
3167 }
3168 else
3169 {
3170 rdistance = rip_distance_new ();
3171 rn->info = rdistance;
3172 }
3173
3174 /* Set distance value. */
3175 rdistance->distance = distance;
3176
3177 /* Reset access-list configuration. */
3178 if (rdistance->access_list)
3179 {
3180 free (rdistance->access_list);
3181 rdistance->access_list = NULL;
3182 }
3183 if (access_list_str)
3184 rdistance->access_list = strdup (access_list_str);
3185
3186 return CMD_SUCCESS;
3187}
3188
pauldc63bfd2005-10-25 23:31:05 +00003189static int
hasso98b718a2004-10-11 12:57:57 +00003190rip_distance_unset (struct vty *vty, const char *distance_str,
3191 const char *ip_str, const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003192{
3193 int ret;
3194 struct prefix_ipv4 p;
paul718e3742002-12-13 20:15:29 +00003195 struct route_node *rn;
3196 struct rip_distance *rdistance;
3197
3198 ret = str2prefix_ipv4 (ip_str, &p);
3199 if (ret == 0)
3200 {
3201 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3202 return CMD_WARNING;
3203 }
3204
paul718e3742002-12-13 20:15:29 +00003205 rn = route_node_lookup (rip_distance_table, (struct prefix *)&p);
3206 if (! rn)
3207 {
3208 vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE);
3209 return CMD_WARNING;
3210 }
3211
3212 rdistance = rn->info;
3213
3214 if (rdistance->access_list)
3215 free (rdistance->access_list);
3216 rip_distance_free (rdistance);
3217
3218 rn->info = NULL;
3219 route_unlock_node (rn);
3220 route_unlock_node (rn);
3221
3222 return CMD_SUCCESS;
3223}
3224
pauldc63bfd2005-10-25 23:31:05 +00003225static void
paul216565a2005-10-25 23:35:28 +00003226rip_distance_reset (void)
paul718e3742002-12-13 20:15:29 +00003227{
3228 struct route_node *rn;
3229 struct rip_distance *rdistance;
3230
3231 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3232 if ((rdistance = rn->info) != NULL)
3233 {
3234 if (rdistance->access_list)
3235 free (rdistance->access_list);
3236 rip_distance_free (rdistance);
3237 rn->info = NULL;
3238 route_unlock_node (rn);
3239 }
3240}
3241
3242/* Apply RIP information to distance method. */
3243u_char
3244rip_distance_apply (struct rip_info *rinfo)
3245{
3246 struct route_node *rn;
3247 struct prefix_ipv4 p;
3248 struct rip_distance *rdistance;
3249 struct access_list *alist;
3250
3251 if (! rip)
3252 return 0;
3253
3254 memset (&p, 0, sizeof (struct prefix_ipv4));
3255 p.family = AF_INET;
3256 p.prefix = rinfo->from;
3257 p.prefixlen = IPV4_MAX_BITLEN;
3258
3259 /* Check source address. */
3260 rn = route_node_match (rip_distance_table, (struct prefix *) &p);
3261 if (rn)
3262 {
3263 rdistance = rn->info;
3264 route_unlock_node (rn);
3265
3266 if (rdistance->access_list)
3267 {
3268 alist = access_list_lookup (AFI_IP, rdistance->access_list);
3269 if (alist == NULL)
3270 return 0;
3271 if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY)
3272 return 0;
3273
3274 return rdistance->distance;
3275 }
3276 else
3277 return rdistance->distance;
3278 }
3279
3280 if (rip->distance)
3281 return rip->distance;
3282
3283 return 0;
3284}
3285
pauldc63bfd2005-10-25 23:31:05 +00003286static void
paul718e3742002-12-13 20:15:29 +00003287rip_distance_show (struct vty *vty)
3288{
3289 struct route_node *rn;
3290 struct rip_distance *rdistance;
3291 int header = 1;
3292 char buf[BUFSIZ];
3293
3294 vty_out (vty, " Distance: (default is %d)%s",
3295 rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT,
3296 VTY_NEWLINE);
3297
3298 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3299 if ((rdistance = rn->info) != NULL)
3300 {
3301 if (header)
3302 {
3303 vty_out (vty, " Address Distance List%s",
3304 VTY_NEWLINE);
3305 header = 0;
3306 }
3307 sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
3308 vty_out (vty, " %-20s %4d %s%s",
3309 buf, rdistance->distance,
3310 rdistance->access_list ? rdistance->access_list : "",
3311 VTY_NEWLINE);
3312 }
3313}
3314
3315DEFUN (rip_distance,
3316 rip_distance_cmd,
3317 "distance <1-255>",
3318 "Administrative distance\n"
3319 "Distance value\n")
3320{
3321 rip->distance = atoi (argv[0]);
3322 return CMD_SUCCESS;
3323}
3324
3325DEFUN (no_rip_distance,
3326 no_rip_distance_cmd,
3327 "no distance <1-255>",
3328 NO_STR
3329 "Administrative distance\n"
3330 "Distance value\n")
3331{
3332 rip->distance = 0;
3333 return CMD_SUCCESS;
3334}
3335
3336DEFUN (rip_distance_source,
3337 rip_distance_source_cmd,
3338 "distance <1-255> A.B.C.D/M",
3339 "Administrative distance\n"
3340 "Distance value\n"
3341 "IP source prefix\n")
3342{
3343 rip_distance_set (vty, argv[0], argv[1], NULL);
3344 return CMD_SUCCESS;
3345}
3346
3347DEFUN (no_rip_distance_source,
3348 no_rip_distance_source_cmd,
3349 "no distance <1-255> A.B.C.D/M",
3350 NO_STR
3351 "Administrative distance\n"
3352 "Distance value\n"
3353 "IP source prefix\n")
3354{
3355 rip_distance_unset (vty, argv[0], argv[1], NULL);
3356 return CMD_SUCCESS;
3357}
3358
3359DEFUN (rip_distance_source_access_list,
3360 rip_distance_source_access_list_cmd,
3361 "distance <1-255> A.B.C.D/M WORD",
3362 "Administrative distance\n"
3363 "Distance value\n"
3364 "IP source prefix\n"
3365 "Access list name\n")
3366{
3367 rip_distance_set (vty, argv[0], argv[1], argv[2]);
3368 return CMD_SUCCESS;
3369}
3370
3371DEFUN (no_rip_distance_source_access_list,
3372 no_rip_distance_source_access_list_cmd,
3373 "no distance <1-255> A.B.C.D/M WORD",
3374 NO_STR
3375 "Administrative distance\n"
3376 "Distance value\n"
3377 "IP source prefix\n"
3378 "Access list name\n")
3379{
3380 rip_distance_unset (vty, argv[0], argv[1], argv[2]);
3381 return CMD_SUCCESS;
3382}
David Lamparter6b0655a2014-06-04 06:53:35 +02003383
Lu Feng0b74a0a2014-07-18 06:13:19 +00003384/* Update ECMP routes to zebra when ECMP is disabled. */
3385static void
3386rip_ecmp_disable (void)
3387{
3388 struct route_node *rp;
3389 struct rip_info *rinfo, *tmp_rinfo;
3390 struct list *list;
3391 struct listnode *node, *nextnode;
3392
3393 if (!rip)
3394 return;
3395
3396 for (rp = route_top (rip->table); rp; rp = route_next (rp))
3397 if ((list = rp->info) != NULL && listcount (list) > 1)
3398 {
3399 rinfo = listgetdata (listhead (list));
3400 if (!rip_route_rte (rinfo))
3401 continue;
3402
3403 /* Drop all other entries, except the first one. */
3404 for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
3405 if (tmp_rinfo != rinfo)
3406 {
3407 RIP_TIMER_OFF (tmp_rinfo->t_timeout);
3408 RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect);
3409 list_delete_node (list, node);
3410 rip_info_free (tmp_rinfo);
3411 }
3412
3413 /* Update zebra. */
3414 rip_zebra_ipv4_add (rp);
3415
3416 /* Set the route change flag. */
3417 SET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
3418
3419 /* Signal the output process to trigger an update. */
3420 rip_event (RIP_TRIGGERED_UPDATE, 0);
3421 }
3422}
3423
3424DEFUN (rip_allow_ecmp,
3425 rip_allow_ecmp_cmd,
3426 "allow-ecmp",
3427 "Allow Equal Cost MultiPath\n")
3428{
3429 if (rip->ecmp)
3430 {
3431 vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE);
3432 return CMD_WARNING;
3433 }
3434
3435 rip->ecmp = 1;
3436 zlog_info ("ECMP is enabled.");
3437 return CMD_SUCCESS;
3438}
3439
3440DEFUN (no_rip_allow_ecmp,
3441 no_rip_allow_ecmp_cmd,
3442 "no allow-ecmp",
3443 NO_STR
3444 "Allow Equal Cost MultiPath\n")
3445{
3446 if (!rip->ecmp)
3447 {
3448 vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE);
3449 return CMD_WARNING;
3450 }
3451
3452 rip->ecmp = 0;
3453 zlog_info ("ECMP is disabled.");
3454 rip_ecmp_disable ();
3455 return CMD_SUCCESS;
3456}
3457
paul718e3742002-12-13 20:15:29 +00003458/* Print out routes update time. */
pauldc63bfd2005-10-25 23:31:05 +00003459static void
paul718e3742002-12-13 20:15:29 +00003460rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo)
3461{
paul718e3742002-12-13 20:15:29 +00003462 time_t clock;
3463 struct tm *tm;
3464#define TIME_BUF 25
3465 char timebuf [TIME_BUF];
3466 struct thread *thread;
3467
paul718e3742002-12-13 20:15:29 +00003468 if ((thread = rinfo->t_timeout) != NULL)
3469 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003470 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003471 tm = gmtime (&clock);
3472 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3473 vty_out (vty, "%5s", timebuf);
3474 }
3475 else if ((thread = rinfo->t_garbage_collect) != NULL)
3476 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003477 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003478 tm = gmtime (&clock);
3479 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3480 vty_out (vty, "%5s", timebuf);
3481 }
3482}
3483
pauldc63bfd2005-10-25 23:31:05 +00003484static const char *
paul718e3742002-12-13 20:15:29 +00003485rip_route_type_print (int sub_type)
3486{
3487 switch (sub_type)
3488 {
3489 case RIP_ROUTE_RTE:
3490 return "n";
3491 case RIP_ROUTE_STATIC:
3492 return "s";
3493 case RIP_ROUTE_DEFAULT:
3494 return "d";
3495 case RIP_ROUTE_REDISTRIBUTE:
3496 return "r";
3497 case RIP_ROUTE_INTERFACE:
3498 return "i";
3499 default:
3500 return "?";
3501 }
3502}
3503
3504DEFUN (show_ip_rip,
3505 show_ip_rip_cmd,
3506 "show ip rip",
3507 SHOW_STR
3508 IP_STR
3509 "Show RIP routes\n")
3510{
3511 struct route_node *np;
Lu Fengb397cf42014-07-18 06:13:18 +00003512 struct rip_info *rinfo = NULL;
3513 struct list *list = NULL;
3514 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00003515
3516 if (! rip)
3517 return CMD_SUCCESS;
3518
hasso16705132003-05-25 14:49:19 +00003519 vty_out (vty, "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s"
3520 "Sub-codes:%s"
3521 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
paul718e3742002-12-13 20:15:29 +00003522 " (i) - interface%s%s"
hassoa1455d82004-03-03 19:36:24 +00003523 " Network Next Hop Metric From Tag Time%s",
hasso16705132003-05-25 14:49:19 +00003524 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003525
3526 for (np = route_top (rip->table); np; np = route_next (np))
Lu Fengb397cf42014-07-18 06:13:18 +00003527 if ((list = np->info) != NULL)
3528 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
paul718e3742002-12-13 20:15:29 +00003529 {
3530 int len;
3531
ajsf52d13c2005-10-01 17:38:06 +00003532 len = vty_out (vty, "%c(%s) %s/%d",
paul718e3742002-12-13 20:15:29 +00003533 /* np->lock, For debugging. */
ajsf52d13c2005-10-01 17:38:06 +00003534 zebra_route_char(rinfo->type),
paul718e3742002-12-13 20:15:29 +00003535 rip_route_type_print (rinfo->sub_type),
3536 inet_ntoa (np->p.u.prefix4), np->p.prefixlen);
3537
hassoa1455d82004-03-03 19:36:24 +00003538 len = 24 - len;
paul718e3742002-12-13 20:15:29 +00003539
3540 if (len > 0)
3541 vty_out (vty, "%*s", len, " ");
3542
3543 if (rinfo->nexthop.s_addr)
3544 vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop),
3545 rinfo->metric);
3546 else
3547 vty_out (vty, "0.0.0.0 %2d ", rinfo->metric);
3548
3549 /* Route which exist in kernel routing table. */
3550 if ((rinfo->type == ZEBRA_ROUTE_RIP) &&
3551 (rinfo->sub_type == RIP_ROUTE_RTE))
3552 {
3553 vty_out (vty, "%-15s ", inet_ntoa (rinfo->from));
hasso16705132003-05-25 14:49:19 +00003554 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003555 rip_vty_out_uptime (vty, rinfo);
3556 }
3557 else if (rinfo->metric == RIP_METRIC_INFINITY)
3558 {
3559 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003560 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003561 rip_vty_out_uptime (vty, rinfo);
3562 }
3563 else
hasso16705132003-05-25 14:49:19 +00003564 {
vincentfbf5d032005-09-29 11:25:50 +00003565 if (rinfo->external_metric)
3566 {
3567 len = vty_out (vty, "self (%s:%d)",
ajsf52d13c2005-10-01 17:38:06 +00003568 zebra_route_string(rinfo->type),
vincentfbf5d032005-09-29 11:25:50 +00003569 rinfo->external_metric);
3570 len = 16 - len;
3571 if (len > 0)
3572 vty_out (vty, "%*s", len, " ");
3573 }
3574 else
3575 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003576 vty_out (vty, "%3d", rinfo->tag);
3577 }
paul718e3742002-12-13 20:15:29 +00003578
3579 vty_out (vty, "%s", VTY_NEWLINE);
3580 }
3581 return CMD_SUCCESS;
3582}
3583
hasso16705132003-05-25 14:49:19 +00003584/* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */
3585DEFUN (show_ip_rip_status,
3586 show_ip_rip_status_cmd,
3587 "show ip rip status",
paul718e3742002-12-13 20:15:29 +00003588 SHOW_STR
3589 IP_STR
hasso16705132003-05-25 14:49:19 +00003590 "Show RIP routes\n"
paul718e3742002-12-13 20:15:29 +00003591 "IP routing protocol process parameters and statistics\n")
3592{
hasso52dc7ee2004-09-23 19:18:23 +00003593 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00003594 struct interface *ifp;
3595 struct rip_interface *ri;
Stephen Hemminger1423c802008-08-14 17:59:25 +01003596 extern const struct message ri_version_msg[];
hasso8a676be2004-10-08 06:36:38 +00003597 const char *send_version;
3598 const char *receive_version;
paul718e3742002-12-13 20:15:29 +00003599
3600 if (! rip)
3601 return CMD_SUCCESS;
3602
3603 vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE);
3604 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
3605 rip->update_time);
Andrew J. Schorra4c64822007-03-21 18:57:38 +00003606 vty_out (vty, " next due in %lu seconds%s",
3607 thread_timer_remain_second(rip->t_update),
paul718e3742002-12-13 20:15:29 +00003608 VTY_NEWLINE);
3609 vty_out (vty, " Timeout after %ld seconds,", rip->timeout_time);
3610 vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time,
3611 VTY_NEWLINE);
3612
3613 /* Filtering status show. */
3614 config_show_distribute (vty);
3615
3616 /* Default metric information. */
3617 vty_out (vty, " Default redistribution metric is %d%s",
3618 rip->default_metric, VTY_NEWLINE);
3619
3620 /* Redistribute information. */
3621 vty_out (vty, " Redistributing:");
3622 config_write_rip_redistribute (vty, 0);
3623 vty_out (vty, "%s", VTY_NEWLINE);
3624
paulf38a4712003-06-07 01:10:00 +00003625 vty_out (vty, " Default version control: send version %s,",
3626 lookup(ri_version_msg,rip->version_send));
3627 if (rip->version_recv == RI_RIP_VERSION_1_AND_2)
3628 vty_out (vty, " receive any version %s", VTY_NEWLINE);
3629 else
3630 vty_out (vty, " receive version %s %s",
3631 lookup(ri_version_msg,rip->version_recv), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003632
3633 vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE);
3634
paul1eb8ef22005-04-07 07:30:20 +00003635 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00003636 {
paul718e3742002-12-13 20:15:29 +00003637 ri = ifp->info;
3638
Stephen Hemminger82f5ee12009-04-07 15:00:46 -07003639 if (!ri->running)
3640 continue;
3641
paul718e3742002-12-13 20:15:29 +00003642 if (ri->enable_network || ri->enable_interface)
3643 {
3644 if (ri->ri_send == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003645 send_version = lookup (ri_version_msg, rip->version_send);
paul718e3742002-12-13 20:15:29 +00003646 else
3647 send_version = lookup (ri_version_msg, ri->ri_send);
3648
3649 if (ri->ri_receive == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003650 receive_version = lookup (ri_version_msg, rip->version_recv);
paul718e3742002-12-13 20:15:29 +00003651 else
3652 receive_version = lookup (ri_version_msg, ri->ri_receive);
3653
3654 vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name,
3655 send_version,
3656 receive_version,
3657 ri->key_chain ? ri->key_chain : "",
3658 VTY_NEWLINE);
3659 }
3660 }
3661
3662 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
3663 config_write_rip_network (vty, 0);
3664
paul4aaff3f2003-06-07 01:04:45 +00003665 {
3666 int found_passive = 0;
paul1eb8ef22005-04-07 07:30:20 +00003667 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul4aaff3f2003-06-07 01:04:45 +00003668 {
paul4aaff3f2003-06-07 01:04:45 +00003669 ri = ifp->info;
3670
3671 if ((ri->enable_network || ri->enable_interface) && ri->passive)
3672 {
3673 if (!found_passive)
3674 {
3675 vty_out (vty, " Passive Interface(s):%s", VTY_NEWLINE);
3676 found_passive = 1;
3677 }
3678 vty_out (vty, " %s%s", ifp->name, VTY_NEWLINE);
3679 }
3680 }
3681 }
3682
paul718e3742002-12-13 20:15:29 +00003683 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
3684 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
3685 rip_peer_display (vty);
3686
3687 rip_distance_show (vty);
3688
3689 return CMD_SUCCESS;
3690}
3691
3692/* RIP configuration write function. */
pauldc63bfd2005-10-25 23:31:05 +00003693static int
paul718e3742002-12-13 20:15:29 +00003694config_write_rip (struct vty *vty)
3695{
3696 int write = 0;
3697 struct route_node *rn;
3698 struct rip_distance *rdistance;
3699
3700 if (rip)
3701 {
3702 /* Router RIP statement. */
3703 vty_out (vty, "router rip%s", VTY_NEWLINE);
3704 write++;
3705
3706 /* RIP version statement. Default is RIP version 2. */
paulf38a4712003-06-07 01:10:00 +00003707 if (rip->version_send != RI_RIP_VERSION_2
3708 || rip->version_recv != RI_RIP_VERSION_1_AND_2)
3709 vty_out (vty, " version %d%s", rip->version_send,
paul718e3742002-12-13 20:15:29 +00003710 VTY_NEWLINE);
3711
3712 /* RIP timer configuration. */
3713 if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT
3714 || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT
3715 || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT)
3716 vty_out (vty, " timers basic %lu %lu %lu%s",
3717 rip->update_time,
3718 rip->timeout_time,
3719 rip->garbage_time,
3720 VTY_NEWLINE);
3721
3722 /* Default information configuration. */
3723 if (rip->default_information)
3724 {
3725 if (rip->default_information_route_map)
3726 vty_out (vty, " default-information originate route-map %s%s",
3727 rip->default_information_route_map, VTY_NEWLINE);
3728 else
3729 vty_out (vty, " default-information originate%s",
3730 VTY_NEWLINE);
3731 }
3732
3733 /* Redistribute configuration. */
3734 config_write_rip_redistribute (vty, 1);
3735
3736 /* RIP offset-list configuration. */
3737 config_write_rip_offset_list (vty);
3738
3739 /* RIP enabled network and interface configuration. */
3740 config_write_rip_network (vty, 1);
3741
3742 /* RIP default metric configuration */
3743 if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT)
3744 vty_out (vty, " default-metric %d%s",
3745 rip->default_metric, VTY_NEWLINE);
3746
3747 /* Distribute configuration. */
3748 write += config_write_distribute (vty);
3749
hasso16705132003-05-25 14:49:19 +00003750 /* Interface routemap configuration */
3751 write += config_write_if_rmap (vty);
3752
paul718e3742002-12-13 20:15:29 +00003753 /* Distance configuration. */
3754 if (rip->distance)
3755 vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE);
3756
3757 /* RIP source IP prefix distance configuration. */
3758 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3759 if ((rdistance = rn->info) != NULL)
3760 vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance,
3761 inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
3762 rdistance->access_list ? rdistance->access_list : "",
3763 VTY_NEWLINE);
3764
Lu Feng0b74a0a2014-07-18 06:13:19 +00003765 /* ECMP configuration. */
3766 if (rip->ecmp)
3767 vty_out (vty, " allow-ecmp%s", VTY_NEWLINE);
3768
paul718e3742002-12-13 20:15:29 +00003769 /* RIP static route configuration. */
3770 for (rn = route_top (rip->route); rn; rn = route_next (rn))
3771 if (rn->info)
3772 vty_out (vty, " route %s/%d%s",
3773 inet_ntoa (rn->p.u.prefix4),
3774 rn->p.prefixlen,
3775 VTY_NEWLINE);
3776
3777 }
3778 return write;
3779}
3780
3781/* RIP node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -08003782static struct cmd_node rip_node =
paul718e3742002-12-13 20:15:29 +00003783{
3784 RIP_NODE,
3785 "%s(config-router)# ",
3786 1
3787};
David Lamparter6b0655a2014-06-04 06:53:35 +02003788
paul718e3742002-12-13 20:15:29 +00003789/* Distribute-list update functions. */
pauldc63bfd2005-10-25 23:31:05 +00003790static void
paul718e3742002-12-13 20:15:29 +00003791rip_distribute_update (struct distribute *dist)
3792{
3793 struct interface *ifp;
3794 struct rip_interface *ri;
3795 struct access_list *alist;
3796 struct prefix_list *plist;
3797
3798 if (! dist->ifname)
3799 return;
3800
3801 ifp = if_lookup_by_name (dist->ifname);
3802 if (ifp == NULL)
3803 return;
3804
3805 ri = ifp->info;
3806
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003807 if (dist->list[DISTRIBUTE_V4_IN])
paul718e3742002-12-13 20:15:29 +00003808 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003809 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_IN]);
paul718e3742002-12-13 20:15:29 +00003810 if (alist)
3811 ri->list[RIP_FILTER_IN] = alist;
3812 else
3813 ri->list[RIP_FILTER_IN] = NULL;
3814 }
3815 else
3816 ri->list[RIP_FILTER_IN] = NULL;
3817
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003818 if (dist->list[DISTRIBUTE_V4_OUT])
paul718e3742002-12-13 20:15:29 +00003819 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003820 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_OUT]);
paul718e3742002-12-13 20:15:29 +00003821 if (alist)
3822 ri->list[RIP_FILTER_OUT] = alist;
3823 else
3824 ri->list[RIP_FILTER_OUT] = NULL;
3825 }
3826 else
3827 ri->list[RIP_FILTER_OUT] = NULL;
3828
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003829 if (dist->prefix[DISTRIBUTE_V4_IN])
paul718e3742002-12-13 20:15:29 +00003830 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003831 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_IN]);
paul718e3742002-12-13 20:15:29 +00003832 if (plist)
3833 ri->prefix[RIP_FILTER_IN] = plist;
3834 else
3835 ri->prefix[RIP_FILTER_IN] = NULL;
3836 }
3837 else
3838 ri->prefix[RIP_FILTER_IN] = NULL;
3839
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003840 if (dist->prefix[DISTRIBUTE_V4_OUT])
paul718e3742002-12-13 20:15:29 +00003841 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003842 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_OUT]);
paul718e3742002-12-13 20:15:29 +00003843 if (plist)
3844 ri->prefix[RIP_FILTER_OUT] = plist;
3845 else
3846 ri->prefix[RIP_FILTER_OUT] = NULL;
3847 }
3848 else
3849 ri->prefix[RIP_FILTER_OUT] = NULL;
3850}
3851
3852void
3853rip_distribute_update_interface (struct interface *ifp)
3854{
3855 struct distribute *dist;
3856
3857 dist = distribute_lookup (ifp->name);
3858 if (dist)
3859 rip_distribute_update (dist);
3860}
3861
3862/* Update all interface's distribute list. */
paul02ff83c2004-06-11 11:27:03 +00003863/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003864static void
paul02ff83c2004-06-11 11:27:03 +00003865rip_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00003866{
3867 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003868 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00003869
paul1eb8ef22005-04-07 07:30:20 +00003870 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3871 rip_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00003872}
paul11dde9c2004-05-31 14:00:00 +00003873/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003874static void
paul11dde9c2004-05-31 14:00:00 +00003875rip_distribute_update_all_wrapper(struct access_list *notused)
3876{
paul02ff83c2004-06-11 11:27:03 +00003877 rip_distribute_update_all(NULL);
paul11dde9c2004-05-31 14:00:00 +00003878}
David Lamparter6b0655a2014-06-04 06:53:35 +02003879
paul718e3742002-12-13 20:15:29 +00003880/* Delete all added rip route. */
3881void
paul216565a2005-10-25 23:35:28 +00003882rip_clean (void)
paul718e3742002-12-13 20:15:29 +00003883{
3884 int i;
3885 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00003886 struct rip_info *rinfo = NULL;
3887 struct list *list = NULL;
3888 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00003889
3890 if (rip)
3891 {
3892 /* Clear RIP routes */
3893 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00003894 if ((list = rp->info) != NULL)
3895 {
3896 rinfo = listgetdata (listhead (list));
3897 if (rip_route_rte (rinfo))
3898 rip_zebra_ipv4_delete (rp);
paul718e3742002-12-13 20:15:29 +00003899
Lu Fengb397cf42014-07-18 06:13:18 +00003900 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
3901 {
3902 RIP_TIMER_OFF (rinfo->t_timeout);
3903 RIP_TIMER_OFF (rinfo->t_garbage_collect);
3904 rip_info_free (rinfo);
3905 }
3906 list_delete (list);
3907 rp->info = NULL;
3908 route_unlock_node (rp);
3909 }
paul718e3742002-12-13 20:15:29 +00003910
3911 /* Cancel RIP related timers. */
3912 RIP_TIMER_OFF (rip->t_update);
3913 RIP_TIMER_OFF (rip->t_triggered_update);
3914 RIP_TIMER_OFF (rip->t_triggered_interval);
3915
3916 /* Cancel read thread. */
3917 if (rip->t_read)
3918 {
3919 thread_cancel (rip->t_read);
3920 rip->t_read = NULL;
3921 }
3922
3923 /* Close RIP socket. */
3924 if (rip->sock >= 0)
3925 {
3926 close (rip->sock);
3927 rip->sock = -1;
3928 }
3929
3930 /* Static RIP route configuration. */
3931 for (rp = route_top (rip->route); rp; rp = route_next (rp))
3932 if (rp->info)
3933 {
3934 rp->info = NULL;
3935 route_unlock_node (rp);
3936 }
3937
3938 /* RIP neighbor configuration. */
3939 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
3940 if (rp->info)
3941 {
3942 rp->info = NULL;
3943 route_unlock_node (rp);
3944 }
3945
3946 /* Redistribute related clear. */
3947 if (rip->default_information_route_map)
3948 free (rip->default_information_route_map);
3949
3950 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
3951 if (rip->route_map[i].name)
3952 free (rip->route_map[i].name);
3953
3954 XFREE (MTYPE_ROUTE_TABLE, rip->table);
3955 XFREE (MTYPE_ROUTE_TABLE, rip->route);
3956 XFREE (MTYPE_ROUTE_TABLE, rip->neighbor);
3957
3958 XFREE (MTYPE_RIP, rip);
3959 rip = NULL;
3960 }
3961
3962 rip_clean_network ();
paul4aaff3f2003-06-07 01:04:45 +00003963 rip_passive_nondefault_clean ();
paul718e3742002-12-13 20:15:29 +00003964 rip_offset_clean ();
Paul Jakmad319a3a2016-05-25 14:47:00 +01003965 rip_interfaces_clean ();
paul718e3742002-12-13 20:15:29 +00003966 rip_distance_reset ();
3967 rip_redistribute_clean ();
3968}
3969
3970/* Reset all values to the default settings. */
3971void
paul216565a2005-10-25 23:35:28 +00003972rip_reset (void)
paul718e3742002-12-13 20:15:29 +00003973{
3974 /* Reset global counters. */
3975 rip_global_route_changes = 0;
3976 rip_global_queries = 0;
3977
3978 /* Call ripd related reset functions. */
3979 rip_debug_reset ();
3980 rip_route_map_reset ();
3981
3982 /* Call library reset functions. */
3983 vty_reset ();
3984 access_list_reset ();
3985 prefix_list_reset ();
3986
3987 distribute_list_reset ();
3988
Paul Jakmad319a3a2016-05-25 14:47:00 +01003989 rip_interfaces_reset ();
paul718e3742002-12-13 20:15:29 +00003990 rip_distance_reset ();
3991
3992 rip_zclient_reset ();
3993}
3994
pauldc63bfd2005-10-25 23:31:05 +00003995static void
hasso16705132003-05-25 14:49:19 +00003996rip_if_rmap_update (struct if_rmap *if_rmap)
3997{
3998 struct interface *ifp;
3999 struct rip_interface *ri;
4000 struct route_map *rmap;
4001
4002 ifp = if_lookup_by_name (if_rmap->ifname);
4003 if (ifp == NULL)
4004 return;
4005
4006 ri = ifp->info;
4007
4008 if (if_rmap->routemap[IF_RMAP_IN])
4009 {
4010 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
4011 if (rmap)
4012 ri->routemap[IF_RMAP_IN] = rmap;
4013 else
4014 ri->routemap[IF_RMAP_IN] = NULL;
4015 }
4016 else
4017 ri->routemap[RIP_FILTER_IN] = NULL;
4018
4019 if (if_rmap->routemap[IF_RMAP_OUT])
4020 {
4021 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
4022 if (rmap)
4023 ri->routemap[IF_RMAP_OUT] = rmap;
4024 else
4025 ri->routemap[IF_RMAP_OUT] = NULL;
4026 }
4027 else
4028 ri->routemap[RIP_FILTER_OUT] = NULL;
4029}
4030
4031void
4032rip_if_rmap_update_interface (struct interface *ifp)
4033{
4034 struct if_rmap *if_rmap;
4035
4036 if_rmap = if_rmap_lookup (ifp->name);
4037 if (if_rmap)
4038 rip_if_rmap_update (if_rmap);
4039}
4040
pauldc63bfd2005-10-25 23:31:05 +00004041static void
hasso16705132003-05-25 14:49:19 +00004042rip_routemap_update_redistribute (void)
4043{
4044 int i;
4045
4046 if (rip)
4047 {
4048 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
4049 {
4050 if (rip->route_map[i].name)
4051 rip->route_map[i].map =
4052 route_map_lookup_by_name (rip->route_map[i].name);
4053 }
4054 }
4055}
4056
paul11dde9c2004-05-31 14:00:00 +00004057/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00004058static void
hasso98b718a2004-10-11 12:57:57 +00004059rip_routemap_update (const char *notused)
hasso16705132003-05-25 14:49:19 +00004060{
4061 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00004062 struct listnode *node, *nnode;
hasso16705132003-05-25 14:49:19 +00004063
paul1eb8ef22005-04-07 07:30:20 +00004064 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
4065 rip_if_rmap_update_interface (ifp);
hasso16705132003-05-25 14:49:19 +00004066
4067 rip_routemap_update_redistribute ();
4068}
4069
paul718e3742002-12-13 20:15:29 +00004070/* Allocate new rip structure and set default value. */
4071void
pauldc63bfd2005-10-25 23:31:05 +00004072rip_init (void)
paul718e3742002-12-13 20:15:29 +00004073{
4074 /* Randomize for triggered update random(). */
Donald Sharpf31bab42015-06-19 19:26:19 -04004075 srandom (time (NULL));
paul718e3742002-12-13 20:15:29 +00004076
4077 /* Install top nodes. */
4078 install_node (&rip_node, config_write_rip);
4079
4080 /* Install rip commands. */
4081 install_element (VIEW_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00004082 install_element (VIEW_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00004083 install_element (CONFIG_NODE, &router_rip_cmd);
4084 install_element (CONFIG_NODE, &no_router_rip_cmd);
4085
4086 install_default (RIP_NODE);
4087 install_element (RIP_NODE, &rip_version_cmd);
4088 install_element (RIP_NODE, &no_rip_version_cmd);
4089 install_element (RIP_NODE, &no_rip_version_val_cmd);
4090 install_element (RIP_NODE, &rip_default_metric_cmd);
4091 install_element (RIP_NODE, &no_rip_default_metric_cmd);
4092 install_element (RIP_NODE, &no_rip_default_metric_val_cmd);
4093 install_element (RIP_NODE, &rip_timers_cmd);
4094 install_element (RIP_NODE, &no_rip_timers_cmd);
hasso16705132003-05-25 14:49:19 +00004095 install_element (RIP_NODE, &no_rip_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00004096 install_element (RIP_NODE, &rip_route_cmd);
4097 install_element (RIP_NODE, &no_rip_route_cmd);
4098 install_element (RIP_NODE, &rip_distance_cmd);
4099 install_element (RIP_NODE, &no_rip_distance_cmd);
4100 install_element (RIP_NODE, &rip_distance_source_cmd);
4101 install_element (RIP_NODE, &no_rip_distance_source_cmd);
4102 install_element (RIP_NODE, &rip_distance_source_access_list_cmd);
4103 install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd);
Lu Feng0b74a0a2014-07-18 06:13:19 +00004104 install_element (RIP_NODE, &rip_allow_ecmp_cmd);
4105 install_element (RIP_NODE, &no_rip_allow_ecmp_cmd);
paul718e3742002-12-13 20:15:29 +00004106
4107 /* Debug related init. */
4108 rip_debug_init ();
4109
paul718e3742002-12-13 20:15:29 +00004110 /* SNMP init. */
4111#ifdef HAVE_SNMP
4112 rip_snmp_init ();
4113#endif /* HAVE_SNMP */
4114
4115 /* Access list install. */
4116 access_list_init ();
paul11dde9c2004-05-31 14:00:00 +00004117 access_list_add_hook (rip_distribute_update_all_wrapper);
4118 access_list_delete_hook (rip_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00004119
4120 /* Prefix list initialize.*/
4121 prefix_list_init ();
4122 prefix_list_add_hook (rip_distribute_update_all);
4123 prefix_list_delete_hook (rip_distribute_update_all);
4124
4125 /* Distribute list install. */
4126 distribute_list_init (RIP_NODE);
4127 distribute_list_add_hook (rip_distribute_update);
4128 distribute_list_delete_hook (rip_distribute_update);
4129
hasso16705132003-05-25 14:49:19 +00004130 /* Route-map */
4131 rip_route_map_init ();
4132 rip_offset_init ();
4133
4134 route_map_add_hook (rip_routemap_update);
4135 route_map_delete_hook (rip_routemap_update);
4136
4137 if_rmap_init (RIP_NODE);
4138 if_rmap_hook_add (rip_if_rmap_update);
4139 if_rmap_hook_delete (rip_if_rmap_update);
4140
paul718e3742002-12-13 20:15:29 +00004141 /* Distance control. */
4142 rip_distance_table = route_table_init ();
4143}