blob: 9d355ecb9e3a0cdf24bc9fe520a8fad2eaeeb063 [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
paul718e3742002-12-13 20:15:29 +0000318rip_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
319{
320 struct distribute *dist;
321 struct access_list *alist;
322 struct prefix_list *plist;
323
324 /* Input distribute-list filtering. */
325 if (ri->list[RIP_FILTER_IN])
326 {
327 if (access_list_apply (ri->list[RIP_FILTER_IN],
328 (struct prefix *) p) == FILTER_DENY)
329 {
330 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000331 zlog_debug ("%s/%d filtered by distribute in",
paul718e3742002-12-13 20:15:29 +0000332 inet_ntoa (p->prefix), p->prefixlen);
333 return -1;
334 }
335 }
336 if (ri->prefix[RIP_FILTER_IN])
337 {
338 if (prefix_list_apply (ri->prefix[RIP_FILTER_IN],
339 (struct prefix *) p) == PREFIX_DENY)
340 {
341 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000342 zlog_debug ("%s/%d filtered by prefix-list in",
paul718e3742002-12-13 20:15:29 +0000343 inet_ntoa (p->prefix), p->prefixlen);
344 return -1;
345 }
346 }
347
348 /* All interface filter check. */
349 dist = distribute_lookup (NULL);
350 if (dist)
351 {
352 if (dist->list[DISTRIBUTE_IN])
353 {
354 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
355
356 if (alist)
357 {
358 if (access_list_apply (alist,
359 (struct prefix *) p) == FILTER_DENY)
360 {
361 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000362 zlog_debug ("%s/%d filtered by distribute in",
paul718e3742002-12-13 20:15:29 +0000363 inet_ntoa (p->prefix), p->prefixlen);
364 return -1;
365 }
366 }
367 }
368 if (dist->prefix[DISTRIBUTE_IN])
369 {
370 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
371
372 if (plist)
373 {
374 if (prefix_list_apply (plist,
375 (struct prefix *) p) == PREFIX_DENY)
376 {
377 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000378 zlog_debug ("%s/%d filtered by prefix-list in",
paul718e3742002-12-13 20:15:29 +0000379 inet_ntoa (p->prefix), p->prefixlen);
380 return -1;
381 }
382 }
383 }
384 }
385 return 0;
386}
387
pauldc63bfd2005-10-25 23:31:05 +0000388static int
paul718e3742002-12-13 20:15:29 +0000389rip_outgoing_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
390{
391 struct distribute *dist;
392 struct access_list *alist;
393 struct prefix_list *plist;
394
395 if (ri->list[RIP_FILTER_OUT])
396 {
397 if (access_list_apply (ri->list[RIP_FILTER_OUT],
398 (struct prefix *) p) == FILTER_DENY)
399 {
400 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000401 zlog_debug ("%s/%d is filtered by distribute out",
paul718e3742002-12-13 20:15:29 +0000402 inet_ntoa (p->prefix), p->prefixlen);
403 return -1;
404 }
405 }
406 if (ri->prefix[RIP_FILTER_OUT])
407 {
408 if (prefix_list_apply (ri->prefix[RIP_FILTER_OUT],
409 (struct prefix *) p) == PREFIX_DENY)
410 {
411 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000412 zlog_debug ("%s/%d is filtered by prefix-list out",
paul718e3742002-12-13 20:15:29 +0000413 inet_ntoa (p->prefix), p->prefixlen);
414 return -1;
415 }
416 }
417
418 /* All interface filter check. */
419 dist = distribute_lookup (NULL);
420 if (dist)
421 {
422 if (dist->list[DISTRIBUTE_OUT])
423 {
424 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
425
426 if (alist)
427 {
428 if (access_list_apply (alist,
429 (struct prefix *) p) == FILTER_DENY)
430 {
431 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000432 zlog_debug ("%s/%d filtered by distribute out",
paul718e3742002-12-13 20:15:29 +0000433 inet_ntoa (p->prefix), p->prefixlen);
434 return -1;
435 }
436 }
437 }
438 if (dist->prefix[DISTRIBUTE_OUT])
439 {
440 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
441
442 if (plist)
443 {
444 if (prefix_list_apply (plist,
445 (struct prefix *) p) == PREFIX_DENY)
446 {
447 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000448 zlog_debug ("%s/%d filtered by prefix-list out",
paul718e3742002-12-13 20:15:29 +0000449 inet_ntoa (p->prefix), p->prefixlen);
450 return -1;
451 }
452 }
453 }
454 }
455 return 0;
456}
457
458/* Check nexthop address validity. */
459static int
460rip_nexthop_check (struct in_addr *addr)
461{
hasso52dc7ee2004-09-23 19:18:23 +0000462 struct listnode *node;
463 struct listnode *cnode;
paul718e3742002-12-13 20:15:29 +0000464 struct interface *ifp;
465 struct connected *ifc;
466 struct prefix *p;
467
468 /* If nexthop address matches local configured address then it is
469 invalid nexthop. */
paul1eb8ef22005-04-07 07:30:20 +0000470 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +0000471 {
paul1eb8ef22005-04-07 07:30:20 +0000472 for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, ifc))
paul718e3742002-12-13 20:15:29 +0000473 {
paul718e3742002-12-13 20:15:29 +0000474 p = ifc->address;
475
476 if (p->family == AF_INET
477 && IPV4_ADDR_SAME (&p->u.prefix4, addr))
478 return -1;
479 }
480 }
481 return 0;
482}
483
484/* RIP add route to routing table. */
pauldc63bfd2005-10-25 23:31:05 +0000485static void
paul718e3742002-12-13 20:15:29 +0000486rip_rte_process (struct rte *rte, struct sockaddr_in *from,
paula87552c2004-05-03 20:00:17 +0000487 struct interface *ifp)
paul718e3742002-12-13 20:15:29 +0000488{
489 int ret;
490 struct prefix_ipv4 p;
491 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +0000492 struct rip_info *rinfo = NULL, newinfo;
paul718e3742002-12-13 20:15:29 +0000493 struct rip_interface *ri;
494 struct in_addr *nexthop;
paul718e3742002-12-13 20:15:29 +0000495 int same = 0;
vincentfbf5d032005-09-29 11:25:50 +0000496 unsigned char old_dist, new_dist;
Lu Fengb397cf42014-07-18 06:13:18 +0000497 struct list *list = NULL;
498 struct listnode *node = NULL;
paul718e3742002-12-13 20:15:29 +0000499
500 /* Make prefix structure. */
501 memset (&p, 0, sizeof (struct prefix_ipv4));
502 p.family = AF_INET;
503 p.prefix = rte->prefix;
504 p.prefixlen = ip_masklen (rte->mask);
505
506 /* Make sure mask is applied. */
507 apply_mask_ipv4 (&p);
508
509 /* Apply input filters. */
510 ri = ifp->info;
511
512 ret = rip_incoming_filter (&p, ri);
513 if (ret < 0)
514 return;
515
Lu Fengb397cf42014-07-18 06:13:18 +0000516 memset (&newinfo, 0, sizeof (newinfo));
517 newinfo.type = ZEBRA_ROUTE_RIP;
518 newinfo.sub_type = RIP_ROUTE_RTE;
519 newinfo.nexthop = rte->nexthop;
520 newinfo.from = from->sin_addr;
521 newinfo.ifindex = ifp->ifindex;
522 newinfo.metric = rte->metric;
523 newinfo.metric_out = rte->metric; /* XXX */
524 newinfo.tag = ntohs (rte->tag); /* XXX */
525
hasso16705132003-05-25 14:49:19 +0000526 /* Modify entry according to the interface routemap. */
527 if (ri->routemap[RIP_FILTER_IN])
528 {
529 int ret;
hasso16705132003-05-25 14:49:19 +0000530
531 /* The object should be of the type of rip_info */
paula87552c2004-05-03 20:00:17 +0000532 ret = route_map_apply (ri->routemap[RIP_FILTER_IN],
533 (struct prefix *) &p, RMAP_RIP, &newinfo);
hasso16705132003-05-25 14:49:19 +0000534
535 if (ret == RMAP_DENYMATCH)
paula87552c2004-05-03 20:00:17 +0000536 {
537 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000538 zlog_debug ("RIP %s/%d is filtered by route-map in",
paula87552c2004-05-03 20:00:17 +0000539 inet_ntoa (p.prefix), p.prefixlen);
540 return;
541 }
hasso16705132003-05-25 14:49:19 +0000542
543 /* Get back the object */
paula87552c2004-05-03 20:00:17 +0000544 rte->nexthop = newinfo.nexthop_out;
545 rte->tag = htons (newinfo.tag_out); /* XXX */
546 rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
hasso16705132003-05-25 14:49:19 +0000547 }
548
paul718e3742002-12-13 20:15:29 +0000549 /* Once the entry has been validated, update the metric by
550 adding the cost of the network on wich the message
551 arrived. If the result is greater than infinity, use infinity
552 (RFC2453 Sec. 3.9.2) */
553 /* Zebra ripd can handle offset-list in. */
554 ret = rip_offset_list_apply_in (&p, ifp, &rte->metric);
555
556 /* If offset-list does not modify the metric use interface's
557 metric. */
paula87552c2004-05-03 20:00:17 +0000558 if (!ret)
Lu Feng7b3b98a2014-04-14 08:09:29 +0000559 rte->metric += ifp->metric ? ifp->metric : 1;
paul718e3742002-12-13 20:15:29 +0000560
561 if (rte->metric > RIP_METRIC_INFINITY)
562 rte->metric = RIP_METRIC_INFINITY;
563
564 /* Set nexthop pointer. */
565 if (rte->nexthop.s_addr == 0)
566 nexthop = &from->sin_addr;
567 else
568 nexthop = &rte->nexthop;
569
hasso16705132003-05-25 14:49:19 +0000570 /* Check if nexthop address is myself, then do nothing. */
paul718e3742002-12-13 20:15:29 +0000571 if (rip_nexthop_check (nexthop) < 0)
572 {
573 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000574 zlog_debug ("Nexthop address %s is myself", inet_ntoa (*nexthop));
paul718e3742002-12-13 20:15:29 +0000575 return;
576 }
577
578 /* Get index for the prefix. */
579 rp = route_node_get (rip->table, (struct prefix *) &p);
580
Lu Fengb397cf42014-07-18 06:13:18 +0000581 newinfo.rp = rp;
582 newinfo.nexthop = *nexthop;
583 newinfo.metric = rte->metric;
584 newinfo.tag = ntohs (rte->tag);
585 newinfo.distance = rip_distance_apply (&newinfo);
586
587 new_dist = newinfo.distance ? newinfo.distance : ZEBRA_RIP_DISTANCE_DEFAULT;
588
paul718e3742002-12-13 20:15:29 +0000589 /* Check to see whether there is already RIP route on the table. */
Lu Fengb397cf42014-07-18 06:13:18 +0000590 if ((list = rp->info) != NULL)
591 for (ALL_LIST_ELEMENTS_RO (list, node, rinfo))
592 {
593 /* Need to compare with redistributed entry or local entry */
594 if (!rip_route_rte (rinfo))
595 break;
596
597 if (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr) &&
598 IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
599 break;
600
601 if (!listnextnode (node))
602 {
603 /* Not found in the list */
604
605 if (rte->metric > rinfo->metric)
606 {
607 /* New route has a greater metric. Discard it. */
608 route_unlock_node (rp);
609 return;
610 }
611
612 if (rte->metric < rinfo->metric)
613 /* New route has a smaller metric. Replace the ECMP list
614 * with the new one in below. */
615 break;
616
617 /* Metrics are same. We compare the distances. */
618 old_dist = rinfo->distance ? \
619 rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT;
620
621 if (new_dist > old_dist)
622 {
623 /* New route has a greater distance. Discard it. */
624 route_unlock_node (rp);
625 return;
626 }
627
628 if (new_dist < old_dist)
629 /* New route has a smaller distance. Replace the ECMP list
630 * with the new one in below. */
631 break;
632
633 /* Metrics and distances are both same. Keep "rinfo" null and
634 * the new route is added in the ECMP list in below. */
635 }
636 }
paul718e3742002-12-13 20:15:29 +0000637
638 if (rinfo)
639 {
paul718e3742002-12-13 20:15:29 +0000640 /* Local static route. */
641 if (rinfo->type == ZEBRA_ROUTE_RIP
paula87552c2004-05-03 20:00:17 +0000642 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
643 (rinfo->sub_type == RIP_ROUTE_DEFAULT))
644 && rinfo->metric != RIP_METRIC_INFINITY)
vincentfbf5d032005-09-29 11:25:50 +0000645 {
646 route_unlock_node (rp);
647 return;
648 }
649
650 /* Redistributed route check. */
651 if (rinfo->type != ZEBRA_ROUTE_RIP
652 && rinfo->metric != RIP_METRIC_INFINITY)
653 {
vincentfbf5d032005-09-29 11:25:50 +0000654 old_dist = rinfo->distance;
David Lamparterb68da442013-02-28 22:17:00 +0100655 /* Only routes directly connected to an interface (nexthop == 0)
656 * may have a valid NULL distance */
657 if (rinfo->nexthop.s_addr != 0)
vincent7a383332006-01-30 18:12:42 +0000658 old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
vincentfbf5d032005-09-29 11:25:50 +0000659 /* If imported route does not have STRICT precedence,
660 mark it as a ghost */
Lu Fengb397cf42014-07-18 06:13:18 +0000661 if (new_dist <= old_dist && rte->metric != RIP_METRIC_INFINITY)
662 rip_ecmp_replace (&newinfo);
663
664 route_unlock_node (rp);
665 return;
vincentfbf5d032005-09-29 11:25:50 +0000666 }
paul718e3742002-12-13 20:15:29 +0000667 }
paula87552c2004-05-03 20:00:17 +0000668
669 if (!rinfo)
paul718e3742002-12-13 20:15:29 +0000670 {
Lu Fengb397cf42014-07-18 06:13:18 +0000671 if (rp->info)
672 route_unlock_node (rp);
673
paul718e3742002-12-13 20:15:29 +0000674 /* Now, check to see whether there is already an explicit route
paula87552c2004-05-03 20:00:17 +0000675 for the destination prefix. If there is no such route, add
676 this route to the routing table, unless the metric is
677 infinity (there is no point in adding a route which
678 unusable). */
paul718e3742002-12-13 20:15:29 +0000679 if (rte->metric != RIP_METRIC_INFINITY)
Lu Fengb397cf42014-07-18 06:13:18 +0000680 rip_ecmp_add (&newinfo);
paul718e3742002-12-13 20:15:29 +0000681 }
682 else
683 {
684 /* Route is there but we are not sure the route is RIP or not. */
paula87552c2004-05-03 20:00:17 +0000685
paul718e3742002-12-13 20:15:29 +0000686 /* If there is an existing route, compare the next hop address
paula87552c2004-05-03 20:00:17 +0000687 to the address of the router from which the datagram came.
688 If this datagram is from the same router as the existing
689 route, reinitialize the timeout. */
hasso16705132003-05-25 14:49:19 +0000690 same = (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr)
paula87552c2004-05-03 20:00:17 +0000691 && (rinfo->ifindex == ifp->ifindex));
paul718e3742002-12-13 20:15:29 +0000692
Lu Fengb397cf42014-07-18 06:13:18 +0000693 old_dist = rinfo->distance ? \
694 rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT;
paulb94f9db2004-05-01 20:45:38 +0000695
paul718e3742002-12-13 20:15:29 +0000696 /* Next, compare the metrics. If the datagram is from the same
paula87552c2004-05-03 20:00:17 +0000697 router as the existing route, and the new metric is different
698 than the old one; or, if the new metric is lower than the old
699 one, or if the tag has been changed; or if there is a route
700 with a lower administrave distance; or an update of the
701 distance on the actual route; do the following actions: */
702 if ((same && rinfo->metric != rte->metric)
703 || (rte->metric < rinfo->metric)
704 || ((same)
705 && (rinfo->metric == rte->metric)
Lu Fengb397cf42014-07-18 06:13:18 +0000706 && (newinfo.tag != rinfo->tag))
707 || (old_dist > new_dist)
708 || ((old_dist != new_dist) && same))
paula87552c2004-05-03 20:00:17 +0000709 {
Lu Fengb397cf42014-07-18 06:13:18 +0000710 if (listcount (list) == 1)
paula87552c2004-05-03 20:00:17 +0000711 {
Lu Fengb397cf42014-07-18 06:13:18 +0000712 if (newinfo.metric != RIP_METRIC_INFINITY)
713 rip_ecmp_replace (&newinfo);
714 else
715 rip_ecmp_delete (rinfo);
paula87552c2004-05-03 20:00:17 +0000716 }
717 else
718 {
Lu Fengb397cf42014-07-18 06:13:18 +0000719 if (newinfo.metric < rinfo->metric)
720 rip_ecmp_replace (&newinfo);
721 else if (newinfo.metric > rinfo->metric)
722 rip_ecmp_delete (rinfo);
723 else if (new_dist < old_dist)
724 rip_ecmp_replace (&newinfo);
725 else if (new_dist > old_dist)
726 rip_ecmp_delete (rinfo);
727 else
728 {
729 int update = CHECK_FLAG (rinfo->flags, RIP_RTF_FIB) ? 1 : 0;
730
731 assert (newinfo.metric != RIP_METRIC_INFINITY);
732
733 RIP_TIMER_OFF (rinfo->t_timeout);
734 RIP_TIMER_OFF (rinfo->t_garbage_collect);
735 memcpy (rinfo, &newinfo, sizeof (struct rip_info));
736 rip_timeout_update (rinfo);
737
738 if (update)
739 rip_zebra_ipv4_add (rp);
740
741 /* - Set the route change flag on the first entry. */
742 rinfo = listgetdata (listhead (list));
743 SET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
744 rip_event (RIP_TRIGGERED_UPDATE, 0);
745 }
paula87552c2004-05-03 20:00:17 +0000746 }
747 }
Lu Fengb397cf42014-07-18 06:13:18 +0000748 else /* same & no change */
749 rip_timeout_update (rinfo);
750
paul718e3742002-12-13 20:15:29 +0000751 /* Unlock tempolary lock of the route. */
752 route_unlock_node (rp);
753 }
754}
755
756/* Dump RIP packet */
pauldc63bfd2005-10-25 23:31:05 +0000757static void
hasso8a676be2004-10-08 06:36:38 +0000758rip_packet_dump (struct rip_packet *packet, int size, const char *sndrcv)
paul718e3742002-12-13 20:15:29 +0000759{
760 caddr_t lim;
761 struct rte *rte;
hasso8a676be2004-10-08 06:36:38 +0000762 const char *command_str;
paul718e3742002-12-13 20:15:29 +0000763 char pbuf[BUFSIZ], nbuf[BUFSIZ];
764 u_char netmask = 0;
765 u_char *p;
766
767 /* Set command string. */
768 if (packet->command > 0 && packet->command < RIP_COMMAND_MAX)
769 command_str = lookup (rip_msg, packet->command);
770 else
771 command_str = "unknown";
772
773 /* Dump packet header. */
ajs5d6c3772004-12-08 19:24:06 +0000774 zlog_debug ("%s %s version %d packet size %d",
paul718e3742002-12-13 20:15:29 +0000775 sndrcv, command_str, packet->version, size);
776
777 /* Dump each routing table entry. */
778 rte = packet->rte;
779
780 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
781 {
782 if (packet->version == RIPv2)
783 {
784 netmask = ip_masklen (rte->mask);
785
paulca5e5162004-06-06 22:06:33 +0000786 if (rte->family == htons (RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +0000787 {
paulca5e5162004-06-06 22:06:33 +0000788 if (rte->tag == htons (RIP_AUTH_SIMPLE_PASSWORD))
paul718e3742002-12-13 20:15:29 +0000789 {
790 p = (u_char *)&rte->prefix;
791
ajs5d6c3772004-12-08 19:24:06 +0000792 zlog_debug (" family 0x%X type %d auth string: %s",
paul718e3742002-12-13 20:15:29 +0000793 ntohs (rte->family), ntohs (rte->tag), p);
794 }
paulca5e5162004-06-06 22:06:33 +0000795 else if (rte->tag == htons (RIP_AUTH_MD5))
paul718e3742002-12-13 20:15:29 +0000796 {
797 struct rip_md5_info *md5;
798
799 md5 = (struct rip_md5_info *) &packet->rte;
800
ajs5d6c3772004-12-08 19:24:06 +0000801 zlog_debug (" family 0x%X type %d (MD5 authentication)",
paul718e3742002-12-13 20:15:29 +0000802 ntohs (md5->family), ntohs (md5->type));
ajs5d6c3772004-12-08 19:24:06 +0000803 zlog_debug (" RIP-2 packet len %d Key ID %d"
paulca5e5162004-06-06 22:06:33 +0000804 " Auth Data len %d",
805 ntohs (md5->packet_len), md5->keyid,
806 md5->auth_len);
ajs5d6c3772004-12-08 19:24:06 +0000807 zlog_debug (" Sequence Number %ld",
paulca5e5162004-06-06 22:06:33 +0000808 (u_long) ntohl (md5->sequence));
paul718e3742002-12-13 20:15:29 +0000809 }
paulca5e5162004-06-06 22:06:33 +0000810 else if (rte->tag == htons (RIP_AUTH_DATA))
paul718e3742002-12-13 20:15:29 +0000811 {
812 p = (u_char *)&rte->prefix;
813
ajs5d6c3772004-12-08 19:24:06 +0000814 zlog_debug (" family 0x%X type %d (MD5 data)",
paul718e3742002-12-13 20:15:29 +0000815 ntohs (rte->family), ntohs (rte->tag));
ajs5d6c3772004-12-08 19:24:06 +0000816 zlog_debug (" MD5: %02X%02X%02X%02X%02X%02X%02X%02X"
paul718e3742002-12-13 20:15:29 +0000817 "%02X%02X%02X%02X%02X%02X%02X",
paulca5e5162004-06-06 22:06:33 +0000818 p[0], p[1], p[2], p[3], p[4], p[5], p[6],
819 p[7], p[9], p[10], p[11], p[12], p[13],
820 p[14], p[15]);
paul718e3742002-12-13 20:15:29 +0000821 }
822 else
823 {
ajs5d6c3772004-12-08 19:24:06 +0000824 zlog_debug (" family 0x%X type %d (Unknown auth type)",
paul718e3742002-12-13 20:15:29 +0000825 ntohs (rte->family), ntohs (rte->tag));
826 }
827 }
828 else
ajs5d6c3772004-12-08 19:24:06 +0000829 zlog_debug (" %s/%d -> %s family %d tag %d metric %ld",
paulca5e5162004-06-06 22:06:33 +0000830 inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
831 netmask, inet_ntop (AF_INET, &rte->nexthop, nbuf,
832 BUFSIZ), ntohs (rte->family),
833 ntohs (rte->tag), (u_long) ntohl (rte->metric));
paul718e3742002-12-13 20:15:29 +0000834 }
835 else
836 {
ajs5d6c3772004-12-08 19:24:06 +0000837 zlog_debug (" %s family %d tag %d metric %ld",
paul718e3742002-12-13 20:15:29 +0000838 inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
839 ntohs (rte->family), ntohs (rte->tag),
840 (u_long)ntohl (rte->metric));
841 }
842 }
843}
844
845/* Check if the destination address is valid (unicast; not net 0
846 or 127) (RFC2453 Section 3.9.2 - Page 26). But we don't
847 check net 0 because we accept default route. */
pauldc63bfd2005-10-25 23:31:05 +0000848static int
paul718e3742002-12-13 20:15:29 +0000849rip_destination_check (struct in_addr addr)
850{
851 u_int32_t destination;
852
853 /* Convert to host byte order. */
854 destination = ntohl (addr.s_addr);
855
856 if (IPV4_NET127 (destination))
857 return 0;
858
859 /* Net 0 may match to the default route. */
860 if (IPV4_NET0 (destination) && destination != 0)
861 return 0;
862
863 /* Unicast address must belong to class A, B, C. */
864 if (IN_CLASSA (destination))
865 return 1;
866 if (IN_CLASSB (destination))
867 return 1;
868 if (IN_CLASSC (destination))
869 return 1;
870
871 return 0;
872}
873
874/* RIP version 2 authentication. */
pauldc63bfd2005-10-25 23:31:05 +0000875static int
paul718e3742002-12-13 20:15:29 +0000876rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from,
877 struct interface *ifp)
878{
879 struct rip_interface *ri;
880 char *auth_str;
881
882 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000883 zlog_debug ("RIPv2 simple password authentication from %s",
paul718e3742002-12-13 20:15:29 +0000884 inet_ntoa (from->sin_addr));
885
886 ri = ifp->info;
887
888 if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD
paulca5e5162004-06-06 22:06:33 +0000889 || rte->tag != htons(RIP_AUTH_SIMPLE_PASSWORD))
paul718e3742002-12-13 20:15:29 +0000890 return 0;
891
892 /* Simple password authentication. */
893 if (ri->auth_str)
894 {
895 auth_str = (char *) &rte->prefix;
896
897 if (strncmp (auth_str, ri->auth_str, 16) == 0)
898 return 1;
899 }
900 if (ri->key_chain)
901 {
902 struct keychain *keychain;
903 struct key *key;
904
905 keychain = keychain_lookup (ri->key_chain);
906 if (keychain == NULL)
907 return 0;
908
909 key = key_match_for_accept (keychain, (char *) &rte->prefix);
910 if (key)
911 return 1;
912 }
913 return 0;
914}
915
916/* RIP version 2 authentication with MD5. */
pauldc63bfd2005-10-25 23:31:05 +0000917static int
paul718e3742002-12-13 20:15:29 +0000918rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from,
paulca5e5162004-06-06 22:06:33 +0000919 int length, struct interface *ifp)
paul718e3742002-12-13 20:15:29 +0000920{
921 struct rip_interface *ri;
922 struct rip_md5_info *md5;
923 struct rip_md5_data *md5data;
924 struct keychain *keychain;
925 struct key *key;
vincentc1a03d42005-09-28 15:47:44 +0000926 MD5_CTX ctx;
paul718e3742002-12-13 20:15:29 +0000927 u_char digest[RIP_AUTH_MD5_SIZE];
928 u_int16_t packet_len;
paul98fd1e62006-01-17 17:26:25 +0000929 char auth_str[RIP_AUTH_MD5_SIZE];
paul718e3742002-12-13 20:15:29 +0000930
931 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000932 zlog_debug ("RIPv2 MD5 authentication from %s",
paulca5e5162004-06-06 22:06:33 +0000933 inet_ntoa (from->sin_addr));
paul718e3742002-12-13 20:15:29 +0000934
935 ri = ifp->info;
936 md5 = (struct rip_md5_info *) &packet->rte;
937
938 /* Check auth type. */
paulca5e5162004-06-06 22:06:33 +0000939 if (ri->auth_type != RIP_AUTH_MD5 || md5->type != htons(RIP_AUTH_MD5))
paul718e3742002-12-13 20:15:29 +0000940 return 0;
941
paulca5e5162004-06-06 22:06:33 +0000942 /* If the authentication length is less than 16, then it must be wrong for
943 * any interpretation of rfc2082. Some implementations also interpret
944 * this as RIP_HEADER_SIZE+ RIP_AUTH_MD5_SIZE, aka RIP_AUTH_MD5_COMPAT_SIZE.
paul98fd1e62006-01-17 17:26:25 +0000945 */
paulca5e5162004-06-06 22:06:33 +0000946 if ( !((md5->auth_len == RIP_AUTH_MD5_SIZE)
947 || (md5->auth_len == RIP_AUTH_MD5_COMPAT_SIZE)))
paulc2bfbcc2004-06-04 01:42:38 +0000948 {
949 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000950 zlog_debug ("RIPv2 MD5 authentication, strange authentication "
paulca5e5162004-06-06 22:06:33 +0000951 "length field %d", md5->auth_len);
paul718e3742002-12-13 20:15:29 +0000952 return 0;
paulc2bfbcc2004-06-04 01:42:38 +0000953 }
paul718e3742002-12-13 20:15:29 +0000954
paulca5e5162004-06-06 22:06:33 +0000955 /* grab and verify check packet length */
956 packet_len = ntohs (md5->packet_len);
957
958 if (packet_len > (length - RIP_HEADER_SIZE - RIP_AUTH_MD5_SIZE))
959 {
960 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000961 zlog_debug ("RIPv2 MD5 authentication, packet length field %d "
paulca5e5162004-06-06 22:06:33 +0000962 "greater than received length %d!",
963 md5->packet_len, length);
964 return 0;
965 }
966
967 /* retrieve authentication data */
968 md5data = (struct rip_md5_data *) (((u_char *) packet) + packet_len);
paul98fd1e62006-01-17 17:26:25 +0000969
970 memset (auth_str, 0, RIP_AUTH_MD5_SIZE);
paulca5e5162004-06-06 22:06:33 +0000971
paul718e3742002-12-13 20:15:29 +0000972 if (ri->key_chain)
973 {
974 keychain = keychain_lookup (ri->key_chain);
975 if (keychain == NULL)
976 return 0;
977
978 key = key_lookup_for_accept (keychain, md5->keyid);
979 if (key == NULL)
980 return 0;
981
paul98fd1e62006-01-17 17:26:25 +0000982 strncpy (auth_str, key->string, RIP_AUTH_MD5_SIZE);
paul718e3742002-12-13 20:15:29 +0000983 }
paul98fd1e62006-01-17 17:26:25 +0000984 else if (ri->auth_str)
985 strncpy (auth_str, ri->auth_str, RIP_AUTH_MD5_SIZE);
paul718e3742002-12-13 20:15:29 +0000986
Paul Jakmafa93b162008-05-29 19:03:08 +0000987 if (auth_str[0] == 0)
paul718e3742002-12-13 20:15:29 +0000988 return 0;
paul98fd1e62006-01-17 17:26:25 +0000989
paul718e3742002-12-13 20:15:29 +0000990 /* MD5 digest authentication. */
vincentc1a03d42005-09-28 15:47:44 +0000991 memset (&ctx, 0, sizeof(ctx));
992 MD5Init(&ctx);
paul98fd1e62006-01-17 17:26:25 +0000993 MD5Update(&ctx, packet, packet_len + RIP_HEADER_SIZE);
994 MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
vincentc1a03d42005-09-28 15:47:44 +0000995 MD5Final(digest, &ctx);
paul98fd1e62006-01-17 17:26:25 +0000996
997 if (memcmp (md5data->digest, digest, RIP_AUTH_MD5_SIZE) == 0)
paul718e3742002-12-13 20:15:29 +0000998 return packet_len;
999 else
1000 return 0;
1001}
1002
paulb14ee002005-02-04 23:42:41 +00001003/* Pick correct auth string for sends, prepare auth_str buffer for use.
1004 * (left justified and padded).
1005 *
1006 * presumes one of ri or key is valid, and that the auth strings they point
1007 * to are nul terminated. If neither are present, auth_str will be fully
1008 * zero padded.
1009 *
1010 */
1011static void
1012rip_auth_prepare_str_send (struct rip_interface *ri, struct key *key,
1013 char *auth_str, int len)
paul718e3742002-12-13 20:15:29 +00001014{
paulb14ee002005-02-04 23:42:41 +00001015 assert (ri || key);
paul718e3742002-12-13 20:15:29 +00001016
paulb14ee002005-02-04 23:42:41 +00001017 memset (auth_str, 0, len);
1018 if (key && key->string)
1019 strncpy (auth_str, key->string, len);
1020 else if (ri->auth_str)
1021 strncpy (auth_str, ri->auth_str, len);
paul718e3742002-12-13 20:15:29 +00001022
paulb14ee002005-02-04 23:42:41 +00001023 return;
1024}
paul718e3742002-12-13 20:15:29 +00001025
paulb14ee002005-02-04 23:42:41 +00001026/* Write RIPv2 simple password authentication information
1027 *
1028 * auth_str is presumed to be 2 bytes and correctly prepared
1029 * (left justified and zero padded).
1030 */
1031static void
1032rip_auth_simple_write (struct stream *s, char *auth_str, int len)
1033{
1034 assert (s && len == RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00001035
paulb14ee002005-02-04 23:42:41 +00001036 stream_putw (s, RIP_FAMILY_AUTH);
1037 stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD);
1038 stream_put (s, auth_str, RIP_AUTH_SIMPLE_SIZE);
1039
1040 return;
1041}
1042
1043/* write RIPv2 MD5 "authentication header"
1044 * (uses the auth key data field)
1045 *
1046 * Digest offset field is set to 0.
1047 *
1048 * returns: offset of the digest offset field, which must be set when
1049 * length to the auth-data MD5 digest is known.
1050 */
1051static size_t
1052rip_auth_md5_ah_write (struct stream *s, struct rip_interface *ri,
1053 struct key *key)
1054{
paul98fd1e62006-01-17 17:26:25 +00001055 size_t doff = 0;
paulb14ee002005-02-04 23:42:41 +00001056
1057 assert (s && ri && ri->auth_type == RIP_AUTH_MD5);
paul718e3742002-12-13 20:15:29 +00001058
1059 /* MD5 authentication. */
paulca5e5162004-06-06 22:06:33 +00001060 stream_putw (s, RIP_FAMILY_AUTH);
paul718e3742002-12-13 20:15:29 +00001061 stream_putw (s, RIP_AUTH_MD5);
1062
paulb14ee002005-02-04 23:42:41 +00001063 /* MD5 AH digest offset field.
1064 *
1065 * Set to placeholder value here, to true value when RIP-2 Packet length
1066 * is known. Actual value is set in .....().
1067 */
paul98fd1e62006-01-17 17:26:25 +00001068 doff = stream_get_endp(s);
paulb14ee002005-02-04 23:42:41 +00001069 stream_putw (s, 0);
paul718e3742002-12-13 20:15:29 +00001070
1071 /* Key ID. */
1072 if (key)
1073 stream_putc (s, key->index % 256);
1074 else
1075 stream_putc (s, 1);
1076
paulca5e5162004-06-06 22:06:33 +00001077 /* Auth Data Len. Set 16 for MD5 authentication data. Older ripds
1078 * however expect RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE so we allow for this
1079 * to be configurable.
1080 */
1081 stream_putc (s, ri->md5_auth_len);
paul718e3742002-12-13 20:15:29 +00001082
1083 /* Sequence Number (non-decreasing). */
1084 /* RFC2080: The value used in the sequence number is
1085 arbitrary, but two suggestions are the time of the
1086 message's creation or a simple message counter. */
1087 stream_putl (s, time (NULL));
1088
1089 /* Reserved field must be zero. */
1090 stream_putl (s, 0);
1091 stream_putl (s, 0);
1092
paul98fd1e62006-01-17 17:26:25 +00001093 return doff;
paulb14ee002005-02-04 23:42:41 +00001094}
paul718e3742002-12-13 20:15:29 +00001095
paulb14ee002005-02-04 23:42:41 +00001096/* If authentication is in used, write the appropriate header
1097 * returns stream offset to which length must later be written
1098 * or 0 if this is not required
1099 */
1100static size_t
1101rip_auth_header_write (struct stream *s, struct rip_interface *ri,
1102 struct key *key, char *auth_str, int len)
1103{
1104 assert (ri->auth_type != RIP_NO_AUTH);
1105
1106 switch (ri->auth_type)
1107 {
1108 case RIP_AUTH_SIMPLE_PASSWORD:
1109 rip_auth_prepare_str_send (ri, key, auth_str, len);
1110 rip_auth_simple_write (s, auth_str, len);
1111 return 0;
1112 case RIP_AUTH_MD5:
1113 return rip_auth_md5_ah_write (s, ri, key);
1114 }
1115 assert (1);
paul98fd1e62006-01-17 17:26:25 +00001116 return 0;
paulb14ee002005-02-04 23:42:41 +00001117}
1118
1119/* Write RIPv2 MD5 authentication data trailer */
1120static void
1121rip_auth_md5_set (struct stream *s, struct rip_interface *ri, size_t doff,
1122 char *auth_str, int authlen)
1123{
1124 unsigned long len;
vincentc1a03d42005-09-28 15:47:44 +00001125 MD5_CTX ctx;
paulb14ee002005-02-04 23:42:41 +00001126 unsigned char digest[RIP_AUTH_MD5_SIZE];
1127
1128 /* Make it sure this interface is configured as MD5
1129 authentication. */
1130 assert ((ri->auth_type == RIP_AUTH_MD5) && (authlen == RIP_AUTH_MD5_SIZE));
1131 assert (doff > 0);
1132
1133 /* Get packet length. */
1134 len = stream_get_endp(s);
1135
1136 /* Check packet length. */
1137 if (len < (RIP_HEADER_SIZE + RIP_RTE_SIZE))
1138 {
1139 zlog_err ("rip_auth_md5_set(): packet length %ld is less than minimum length.", len);
1140 return;
1141 }
1142
1143 /* Set the digest offset length in the header */
1144 stream_putw_at (s, doff, len);
1145
paul718e3742002-12-13 20:15:29 +00001146 /* Set authentication data. */
paulca5e5162004-06-06 22:06:33 +00001147 stream_putw (s, RIP_FAMILY_AUTH);
1148 stream_putw (s, RIP_AUTH_DATA);
paul718e3742002-12-13 20:15:29 +00001149
1150 /* Generate a digest for the RIP packet. */
vincentc1a03d42005-09-28 15:47:44 +00001151 memset(&ctx, 0, sizeof(ctx));
1152 MD5Init(&ctx);
paul98fd1e62006-01-17 17:26:25 +00001153 MD5Update(&ctx, STREAM_DATA (s), stream_get_endp (s));
vincentc1a03d42005-09-28 15:47:44 +00001154 MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
1155 MD5Final(digest, &ctx);
paul718e3742002-12-13 20:15:29 +00001156
1157 /* Copy the digest to the packet. */
1158 stream_write (s, digest, RIP_AUTH_MD5_SIZE);
1159}
1160
1161/* RIP routing information. */
pauldc63bfd2005-10-25 23:31:05 +00001162static void
paul718e3742002-12-13 20:15:29 +00001163rip_response_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001164 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001165{
1166 caddr_t lim;
1167 struct rte *rte;
paul727d1042002-12-13 20:50:29 +00001168 struct prefix_ipv4 ifaddr;
1169 struct prefix_ipv4 ifaddrclass;
paul727d1042002-12-13 20:50:29 +00001170 int subnetted;
paul718e3742002-12-13 20:15:29 +00001171
paul727d1042002-12-13 20:50:29 +00001172 /* We don't know yet. */
1173 subnetted = -1;
1174
paul718e3742002-12-13 20:15:29 +00001175 /* The Response must be ignored if it is not from the RIP
1176 port. (RFC2453 - Sec. 3.9.2)*/
paulca5e5162004-06-06 22:06:33 +00001177 if (from->sin_port != htons(RIP_PORT_DEFAULT))
paul718e3742002-12-13 20:15:29 +00001178 {
1179 zlog_info ("response doesn't come from RIP port: %d",
1180 from->sin_port);
1181 rip_peer_bad_packet (from);
1182 return;
1183 }
1184
1185 /* The datagram's IPv4 source address should be checked to see
1186 whether the datagram is from a valid neighbor; the source of the
ajs35a60c22005-10-30 23:51:32 +00001187 datagram must be on a directly connected network (RFC2453 - Sec. 3.9.2) */
1188 if (if_lookup_address(from->sin_addr) == NULL)
paul718e3742002-12-13 20:15:29 +00001189 {
1190 zlog_info ("This datagram doesn't came from a valid neighbor: %s",
1191 inet_ntoa (from->sin_addr));
1192 rip_peer_bad_packet (from);
1193 return;
1194 }
1195
1196 /* It is also worth checking to see whether the response is from one
1197 of the router's own addresses. */
1198
1199 ; /* Alredy done in rip_read () */
1200
1201 /* Update RIP peer. */
1202 rip_peer_update (from, packet->version);
1203
1204 /* Set RTE pointer. */
1205 rte = packet->rte;
1206
1207 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
1208 {
1209 /* RIPv2 authentication check. */
1210 /* If the Address Family Identifier of the first (and only the
1211 first) entry in the message is 0xFFFF, then the remainder of
1212 the entry contains the authentication. */
1213 /* If the packet gets here it means authentication enabled */
1214 /* Check is done in rip_read(). So, just skipping it */
1215 if (packet->version == RIPv2 &&
1216 rte == packet->rte &&
paulca5e5162004-06-06 22:06:33 +00001217 rte->family == htons(RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +00001218 continue;
1219
paulca5e5162004-06-06 22:06:33 +00001220 if (rte->family != htons(AF_INET))
paul718e3742002-12-13 20:15:29 +00001221 {
1222 /* Address family check. RIP only supports AF_INET. */
1223 zlog_info ("Unsupported family %d from %s.",
1224 ntohs (rte->family), inet_ntoa (from->sin_addr));
1225 continue;
1226 }
1227
1228 /* - is the destination address valid (e.g., unicast; not net 0
1229 or 127) */
1230 if (! rip_destination_check (rte->prefix))
1231 {
1232 zlog_info ("Network is net 0 or net 127 or it is not unicast network");
1233 rip_peer_bad_route (from);
1234 continue;
1235 }
1236
1237 /* Convert metric value to host byte order. */
1238 rte->metric = ntohl (rte->metric);
1239
1240 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1241 if (! (rte->metric >= 1 && rte->metric <= 16))
1242 {
1243 zlog_info ("Route's metric is not in the 1-16 range.");
1244 rip_peer_bad_route (from);
1245 continue;
1246 }
1247
1248 /* RIPv1 does not have nexthop value. */
1249 if (packet->version == RIPv1 && rte->nexthop.s_addr != 0)
1250 {
1251 zlog_info ("RIPv1 packet with nexthop value %s",
1252 inet_ntoa (rte->nexthop));
1253 rip_peer_bad_route (from);
1254 continue;
1255 }
1256
1257 /* That is, if the provided information is ignored, a possibly
1258 sub-optimal, but absolutely valid, route may be taken. If
1259 the received Next Hop is not directly reachable, it should be
1260 treated as 0.0.0.0. */
1261 if (packet->version == RIPv2 && rte->nexthop.s_addr != 0)
1262 {
1263 u_int32_t addrval;
1264
1265 /* Multicast address check. */
1266 addrval = ntohl (rte->nexthop.s_addr);
1267 if (IN_CLASSD (addrval))
1268 {
1269 zlog_info ("Nexthop %s is multicast address, skip this rte",
1270 inet_ntoa (rte->nexthop));
1271 continue;
1272 }
1273
1274 if (! if_lookup_address (rte->nexthop))
1275 {
1276 struct route_node *rn;
1277 struct rip_info *rinfo;
1278
1279 rn = route_node_match_ipv4 (rip->table, &rte->nexthop);
1280
1281 if (rn)
1282 {
1283 rinfo = rn->info;
1284
1285 if (rinfo->type == ZEBRA_ROUTE_RIP
1286 && rinfo->sub_type == RIP_ROUTE_RTE)
1287 {
1288 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001289 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 +00001290 rte->nexthop = rinfo->from;
1291 }
1292 else
1293 {
1294 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001295 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 +00001296 rte->nexthop.s_addr = 0;
1297 }
1298
1299 route_unlock_node (rn);
1300 }
1301 else
1302 {
1303 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001304 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 +00001305 rte->nexthop.s_addr = 0;
1306 }
1307
1308 }
1309 }
1310
1311 /* For RIPv1, there won't be a valid netmask.
1312
1313 This is a best guess at the masks. If everyone was using old
1314 Ciscos before the 'ip subnet zero' option, it would be almost
1315 right too :-)
1316
1317 Cisco summarize ripv1 advertisments to the classful boundary
1318 (/16 for class B's) except when the RIP packet does to inside
1319 the classful network in question. */
1320
1321 if ((packet->version == RIPv1 && rte->prefix.s_addr != 0)
1322 || (packet->version == RIPv2
1323 && (rte->prefix.s_addr != 0 && rte->mask.s_addr == 0)))
1324 {
1325 u_int32_t destination;
1326
paul727d1042002-12-13 20:50:29 +00001327 if (subnetted == -1)
paulc49ad8f2004-10-22 10:27:28 +00001328 {
1329 memcpy (&ifaddr, ifc->address, sizeof (struct prefix_ipv4));
1330 memcpy (&ifaddrclass, &ifaddr, sizeof (struct prefix_ipv4));
1331 apply_classful_mask_ipv4 (&ifaddrclass);
1332 subnetted = 0;
1333 if (ifaddr.prefixlen > ifaddrclass.prefixlen)
1334 subnetted = 1;
1335 }
paul727d1042002-12-13 20:50:29 +00001336
paul718e3742002-12-13 20:15:29 +00001337 destination = ntohl (rte->prefix.s_addr);
1338
paul727d1042002-12-13 20:50:29 +00001339 if (IN_CLASSA (destination))
paul718e3742002-12-13 20:15:29 +00001340 masklen2ip (8, &rte->mask);
paul727d1042002-12-13 20:50:29 +00001341 else if (IN_CLASSB (destination))
1342 masklen2ip (16, &rte->mask);
1343 else if (IN_CLASSC (destination))
1344 masklen2ip (24, &rte->mask);
1345
1346 if (subnetted == 1)
1347 masklen2ip (ifaddrclass.prefixlen,
1348 (struct in_addr *) &destination);
1349 if ((subnetted == 1) && ((rte->prefix.s_addr & destination) ==
1350 ifaddrclass.prefix.s_addr))
1351 {
1352 masklen2ip (ifaddr.prefixlen, &rte->mask);
1353 if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
1354 masklen2ip (32, &rte->mask);
1355 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001356 zlog_debug ("Subnetted route %s", inet_ntoa (rte->prefix));
paul727d1042002-12-13 20:50:29 +00001357 }
1358 else
1359 {
1360 if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
1361 continue;
1362 }
1363
1364 if (IS_RIP_DEBUG_EVENT)
1365 {
ajs5d6c3772004-12-08 19:24:06 +00001366 zlog_debug ("Resultant route %s", inet_ntoa (rte->prefix));
1367 zlog_debug ("Resultant mask %s", inet_ntoa (rte->mask));
paul718e3742002-12-13 20:15:29 +00001368 }
1369 }
1370
1371 /* In case of RIPv2, if prefix in RTE is not netmask applied one
1372 ignore the entry. */
1373 if ((packet->version == RIPv2)
1374 && (rte->mask.s_addr != 0)
1375 && ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr))
1376 {
1377 zlog_warn ("RIPv2 address %s is not mask /%d applied one",
1378 inet_ntoa (rte->prefix), ip_masklen (rte->mask));
1379 rip_peer_bad_route (from);
1380 continue;
1381 }
1382
1383 /* Default route's netmask is ignored. */
1384 if (packet->version == RIPv2
1385 && (rte->prefix.s_addr == 0)
1386 && (rte->mask.s_addr != 0))
1387 {
1388 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001389 zlog_debug ("Default route with non-zero netmask. Set zero to netmask");
paul718e3742002-12-13 20:15:29 +00001390 rte->mask.s_addr = 0;
1391 }
1392
1393 /* Routing table updates. */
paulc49ad8f2004-10-22 10:27:28 +00001394 rip_rte_process (rte, from, ifc->ifp);
paul718e3742002-12-13 20:15:29 +00001395 }
1396}
1397
paula4e987e2005-06-03 17:46:49 +00001398/* Make socket for RIP protocol. */
paulf69bd9d2005-06-03 18:01:50 +00001399static int
paul2c61ae32005-08-16 15:22:14 +00001400rip_create_socket (struct sockaddr_in *from)
paula4e987e2005-06-03 17:46:49 +00001401{
1402 int ret;
1403 int sock;
1404 struct sockaddr_in addr;
paulf69bd9d2005-06-03 18:01:50 +00001405
paul2c61ae32005-08-16 15:22:14 +00001406 memset (&addr, 0, sizeof (struct sockaddr_in));
1407
1408 if (!from)
paulf69bd9d2005-06-03 18:01:50 +00001409 {
paulf69bd9d2005-06-03 18:01:50 +00001410 addr.sin_family = AF_INET;
1411 addr.sin_addr.s_addr = INADDR_ANY;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001412#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001413 addr.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001414#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
jardin38d3c162005-10-19 19:29:59 +00001415 } else {
1416 memcpy(&addr, from, sizeof(addr));
paulf69bd9d2005-06-03 18:01:50 +00001417 }
1418
paul2c61ae32005-08-16 15:22:14 +00001419 /* sending port must always be the RIP port */
1420 addr.sin_port = htons (RIP_PORT_DEFAULT);
1421
paula4e987e2005-06-03 17:46:49 +00001422 /* Make datagram socket. */
1423 sock = socket (AF_INET, SOCK_DGRAM, 0);
1424 if (sock < 0)
1425 {
1426 zlog_err("Cannot create UDP socket: %s", safe_strerror(errno));
1427 exit (1);
1428 }
1429
1430 sockopt_broadcast (sock);
1431 sockopt_reuseaddr (sock);
1432 sockopt_reuseport (sock);
paula4e987e2005-06-03 17:46:49 +00001433#ifdef RIP_RECVMSG
1434 setsockopt_pktinfo (sock);
1435#endif /* RIP_RECVMSG */
Stephen Hemminger78b31d52009-07-21 16:27:26 -07001436#ifdef IPTOS_PREC_INTERNETCONTROL
1437 setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
1438#endif
paula4e987e2005-06-03 17:46:49 +00001439
1440 if (ripd_privs.change (ZPRIVS_RAISE))
1441 zlog_err ("rip_create_socket: could not raise privs");
paulf69bd9d2005-06-03 18:01:50 +00001442 setsockopt_so_recvbuf (sock, RIP_UDP_RCV_BUF);
1443 if ( (ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr))) < 0)
1444
paula4e987e2005-06-03 17:46:49 +00001445 {
1446 int save_errno = errno;
1447 if (ripd_privs.change (ZPRIVS_LOWER))
1448 zlog_err ("rip_create_socket: could not lower privs");
paul2c61ae32005-08-16 15:22:14 +00001449
1450 zlog_err("%s: Can't bind socket %d to %s port %d: %s", __func__,
1451 sock, inet_ntoa(addr.sin_addr),
1452 (int) ntohs(addr.sin_port),
1453 safe_strerror(save_errno));
1454
paulf69bd9d2005-06-03 18:01:50 +00001455 close (sock);
paula4e987e2005-06-03 17:46:49 +00001456 return ret;
1457 }
paulf69bd9d2005-06-03 18:01:50 +00001458
paula4e987e2005-06-03 17:46:49 +00001459 if (ripd_privs.change (ZPRIVS_LOWER))
1460 zlog_err ("rip_create_socket: could not lower privs");
1461
1462 return sock;
1463}
1464
paulc49ad8f2004-10-22 10:27:28 +00001465/* RIP packet send to destination address, on interface denoted by
1466 * by connected argument. NULL to argument denotes destination should be
1467 * should be RIP multicast group
1468 */
pauldc63bfd2005-10-25 23:31:05 +00001469static int
paulc49ad8f2004-10-22 10:27:28 +00001470rip_send_packet (u_char * buf, int size, struct sockaddr_in *to,
1471 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001472{
paul931cd542004-01-23 15:31:42 +00001473 int ret, send_sock;
paul718e3742002-12-13 20:15:29 +00001474 struct sockaddr_in sin;
paulc49ad8f2004-10-22 10:27:28 +00001475
1476 assert (ifc != NULL);
1477
paul931cd542004-01-23 15:31:42 +00001478 if (IS_RIP_DEBUG_PACKET)
1479 {
paulf69bd9d2005-06-03 18:01:50 +00001480#define ADDRESS_SIZE 20
1481 char dst[ADDRESS_SIZE];
1482 dst[ADDRESS_SIZE - 1] = '\0';
1483
paul931cd542004-01-23 15:31:42 +00001484 if (to)
1485 {
paulf69bd9d2005-06-03 18:01:50 +00001486 strncpy (dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001487 }
1488 else
1489 {
1490 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paulf69bd9d2005-06-03 18:01:50 +00001491 strncpy (dst, inet_ntoa(sin.sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001492 }
paulf69bd9d2005-06-03 18:01:50 +00001493#undef ADDRESS_SIZE
ajs5d6c3772004-12-08 19:24:06 +00001494 zlog_debug("rip_send_packet %s > %s (%s)",
paulc49ad8f2004-10-22 10:27:28 +00001495 inet_ntoa(ifc->address->u.prefix4),
1496 dst, ifc->ifp->name);
paul931cd542004-01-23 15:31:42 +00001497 }
paulf69bd9d2005-06-03 18:01:50 +00001498
paulc49ad8f2004-10-22 10:27:28 +00001499 if ( CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY) )
paul931cd542004-01-23 15:31:42 +00001500 {
1501 /*
1502 * ZEBRA_IFA_SECONDARY is set on linux when an interface is configured
1503 * with multiple addresses on the same subnet: the first address
1504 * on the subnet is configured "primary", and all subsequent addresses
1505 * on that subnet are treated as "secondary" addresses.
1506 * In order to avoid routing-table bloat on other rip listeners,
1507 * we do not send out RIP packets with ZEBRA_IFA_SECONDARY source addrs.
1508 * XXX Since Linux is the only system for which the ZEBRA_IFA_SECONDARY
1509 * flag is set, we would end up sending a packet for a "secondary"
1510 * source address on non-linux systems.
1511 */
1512 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001513 zlog_debug("duplicate dropped");
paul931cd542004-01-23 15:31:42 +00001514 return 0;
1515 }
1516
paul718e3742002-12-13 20:15:29 +00001517 /* Make destination address. */
1518 memset (&sin, 0, sizeof (struct sockaddr_in));
1519 sin.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001520#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +00001521 sin.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001522#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +00001523
1524 /* When destination is specified, use it's port and address. */
1525 if (to)
1526 {
paul718e3742002-12-13 20:15:29 +00001527 sin.sin_port = to->sin_port;
1528 sin.sin_addr = to->sin_addr;
paul931cd542004-01-23 15:31:42 +00001529 send_sock = rip->sock;
paul718e3742002-12-13 20:15:29 +00001530 }
1531 else
1532 {
paul2c61ae32005-08-16 15:22:14 +00001533 struct sockaddr_in from;
1534
paul718e3742002-12-13 20:15:29 +00001535 sin.sin_port = htons (RIP_PORT_DEFAULT);
1536 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paul2c61ae32005-08-16 15:22:14 +00001537
1538 /* multicast send should bind to local interface address */
Nick Hilliardbb2315f2012-08-18 15:10:57 +00001539 memset (&from, 0, sizeof (from));
paul2c61ae32005-08-16 15:22:14 +00001540 from.sin_family = AF_INET;
1541 from.sin_port = htons (RIP_PORT_DEFAULT);
1542 from.sin_addr = ifc->address->u.prefix4;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001543#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001544 from.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001545#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul2c61ae32005-08-16 15:22:14 +00001546
paul931cd542004-01-23 15:31:42 +00001547 /*
1548 * we have to open a new socket for each packet because this
1549 * is the most portable way to bind to a different source
1550 * ipv4 address for each packet.
1551 */
paul2c61ae32005-08-16 15:22:14 +00001552 if ( (send_sock = rip_create_socket (&from)) < 0)
paul931cd542004-01-23 15:31:42 +00001553 {
paulf69bd9d2005-06-03 18:01:50 +00001554 zlog_warn("rip_send_packet could not create socket.");
paul931cd542004-01-23 15:31:42 +00001555 return -1;
paulf69bd9d2005-06-03 18:01:50 +00001556 }
paulc49ad8f2004-10-22 10:27:28 +00001557 rip_interface_multicast_set (send_sock, ifc);
paul718e3742002-12-13 20:15:29 +00001558 }
1559
paul931cd542004-01-23 15:31:42 +00001560 ret = sendto (send_sock, buf, size, 0, (struct sockaddr *)&sin,
paul718e3742002-12-13 20:15:29 +00001561 sizeof (struct sockaddr_in));
1562
1563 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001564 zlog_debug ("SEND to %s.%d", inet_ntoa(sin.sin_addr),
paulcc1131a2003-10-15 23:20:17 +00001565 ntohs (sin.sin_port));
paul718e3742002-12-13 20:15:29 +00001566
1567 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001568 zlog_warn ("can't send packet : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001569
paul931cd542004-01-23 15:31:42 +00001570 if (!to)
1571 close(send_sock);
1572
paul718e3742002-12-13 20:15:29 +00001573 return ret;
1574}
1575
1576/* Add redistributed route to RIP table. */
1577void
1578rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
vincentfbf5d032005-09-29 11:25:50 +00001579 unsigned int ifindex, struct in_addr *nexthop,
1580 unsigned int metric, unsigned char distance)
paul718e3742002-12-13 20:15:29 +00001581{
1582 int ret;
Lu Fengb397cf42014-07-18 06:13:18 +00001583 struct route_node *rp = NULL;
1584 struct rip_info *rinfo = NULL, newinfo;
1585 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +00001586
1587 /* Redistribute route */
1588 ret = rip_destination_check (p->prefix);
1589 if (! ret)
1590 return;
1591
1592 rp = route_node_get (rip->table, (struct prefix *) p);
1593
Lu Fengb397cf42014-07-18 06:13:18 +00001594 memset (&newinfo, 0, sizeof (struct rip_info));
1595 newinfo.type = type;
1596 newinfo.sub_type = sub_type;
1597 newinfo.ifindex = ifindex;
1598 newinfo.metric = 1;
1599 newinfo.external_metric = metric;
1600 newinfo.distance = distance;
1601 newinfo.rp = rp;
1602 if (nexthop)
1603 newinfo.nexthop = *nexthop;
paul718e3742002-12-13 20:15:29 +00001604
Lu Fengb397cf42014-07-18 06:13:18 +00001605 if ((list = rp->info) != NULL && listcount (list) != 0)
paul718e3742002-12-13 20:15:29 +00001606 {
Lu Fengb397cf42014-07-18 06:13:18 +00001607 rinfo = listgetdata (listhead (list));
1608
paul718e3742002-12-13 20:15:29 +00001609 if (rinfo->type == ZEBRA_ROUTE_CONNECT
1610 && rinfo->sub_type == RIP_ROUTE_INTERFACE
1611 && rinfo->metric != RIP_METRIC_INFINITY)
1612 {
1613 route_unlock_node (rp);
1614 return;
1615 }
1616
1617 /* Manually configured RIP route check. */
1618 if (rinfo->type == ZEBRA_ROUTE_RIP
hasso16705132003-05-25 14:49:19 +00001619 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
1620 (rinfo->sub_type == RIP_ROUTE_DEFAULT)) )
paul718e3742002-12-13 20:15:29 +00001621 {
hasso16705132003-05-25 14:49:19 +00001622 if (type != ZEBRA_ROUTE_RIP || ((sub_type != RIP_ROUTE_STATIC) &&
1623 (sub_type != RIP_ROUTE_DEFAULT)))
paul718e3742002-12-13 20:15:29 +00001624 {
1625 route_unlock_node (rp);
1626 return;
1627 }
1628 }
1629
Lu Fengb397cf42014-07-18 06:13:18 +00001630 rinfo = rip_ecmp_replace (&newinfo);
1631 route_unlock_node (rp);
paul718e3742002-12-13 20:15:29 +00001632 }
Lu Fengb397cf42014-07-18 06:13:18 +00001633 else
1634 rinfo = rip_ecmp_add (&newinfo);
paul718e3742002-12-13 20:15:29 +00001635
hasso16705132003-05-25 14:49:19 +00001636 if (IS_RIP_DEBUG_EVENT) {
1637 if (!nexthop)
ajs5d6c3772004-12-08 19:24:06 +00001638 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso16705132003-05-25 14:49:19 +00001639 inet_ntoa(p->prefix), p->prefixlen,
1640 ifindex2ifname(ifindex));
1641 else
ajs5d6c3772004-12-08 19:24:06 +00001642 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso16705132003-05-25 14:49:19 +00001643 inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop),
1644 ifindex2ifname(ifindex));
1645 }
1646
paul718e3742002-12-13 20:15:29 +00001647 rip_event (RIP_TRIGGERED_UPDATE, 0);
1648}
1649
1650/* Delete redistributed route from RIP table. */
1651void
1652rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,
1653 unsigned int ifindex)
1654{
1655 int ret;
1656 struct route_node *rp;
1657 struct rip_info *rinfo;
1658
1659 ret = rip_destination_check (p->prefix);
1660 if (! ret)
1661 return;
1662
1663 rp = route_node_lookup (rip->table, (struct prefix *) p);
1664 if (rp)
1665 {
Lu Fengb397cf42014-07-18 06:13:18 +00001666 struct list *list = rp->info;
paul718e3742002-12-13 20:15:29 +00001667
Lu Fengb397cf42014-07-18 06:13:18 +00001668 if (list != NULL && listcount (list) != 0)
1669 {
1670 rinfo = listgetdata (listhead (list));
1671 if (rinfo != NULL
1672 && rinfo->type == type
1673 && rinfo->sub_type == sub_type
1674 && rinfo->ifindex == ifindex)
1675 {
1676 /* Perform poisoned reverse. */
1677 rinfo->metric = RIP_METRIC_INFINITY;
1678 RIP_TIMER_ON (rinfo->t_garbage_collect,
1679 rip_garbage_collect, rip->garbage_time);
1680 RIP_TIMER_OFF (rinfo->t_timeout);
1681 rinfo->flags |= RIP_RTF_CHANGED;
paul718e3742002-12-13 20:15:29 +00001682
Lu Fengb397cf42014-07-18 06:13:18 +00001683 if (IS_RIP_DEBUG_EVENT)
1684 zlog_debug ("Poisone %s/%d on the interface %s with an "
1685 "infinity metric [delete]",
1686 inet_ntoa(p->prefix), p->prefixlen,
1687 ifindex2ifname(ifindex));
hasso16705132003-05-25 14:49:19 +00001688
Lu Fengb397cf42014-07-18 06:13:18 +00001689 rip_event (RIP_TRIGGERED_UPDATE, 0);
1690 }
1691 }
1692 route_unlock_node (rp);
paul718e3742002-12-13 20:15:29 +00001693 }
1694}
1695
1696/* Response to request called from rip_read ().*/
pauldc63bfd2005-10-25 23:31:05 +00001697static void
paul718e3742002-12-13 20:15:29 +00001698rip_request_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001699 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001700{
1701 caddr_t lim;
1702 struct rte *rte;
1703 struct prefix_ipv4 p;
1704 struct route_node *rp;
1705 struct rip_info *rinfo;
1706 struct rip_interface *ri;
1707
hasso16705132003-05-25 14:49:19 +00001708 /* Does not reponse to the requests on the loopback interfaces */
paulc49ad8f2004-10-22 10:27:28 +00001709 if (if_is_loopback (ifc->ifp))
hasso16705132003-05-25 14:49:19 +00001710 return;
1711
hasso429a0f82004-02-22 23:42:22 +00001712 /* Check RIP process is enabled on this interface. */
paulc49ad8f2004-10-22 10:27:28 +00001713 ri = ifc->ifp->info;
hasso16705132003-05-25 14:49:19 +00001714 if (! ri->running)
1715 return;
paul718e3742002-12-13 20:15:29 +00001716
1717 /* When passive interface is specified, suppress responses */
1718 if (ri->passive)
1719 return;
paulc49ad8f2004-10-22 10:27:28 +00001720
paul718e3742002-12-13 20:15:29 +00001721 /* RIP peer update. */
1722 rip_peer_update (from, packet->version);
1723
1724 lim = ((caddr_t) packet) + size;
1725 rte = packet->rte;
1726
1727 /* The Request is processed entry by entry. If there are no
1728 entries, no response is given. */
1729 if (lim == (caddr_t) rte)
1730 return;
1731
1732 /* There is one special case. If there is exactly one entry in the
1733 request, and it has an address family identifier of zero and a
1734 metric of infinity (i.e., 16), then this is a request to send the
1735 entire routing table. */
1736 if (lim == ((caddr_t) (rte + 1)) &&
1737 ntohs (rte->family) == 0 &&
1738 ntohl (rte->metric) == RIP_METRIC_INFINITY)
1739 {
1740 /* All route with split horizon */
paulc49ad8f2004-10-22 10:27:28 +00001741 rip_output_process (ifc, from, rip_all_route, packet->version);
paul718e3742002-12-13 20:15:29 +00001742 }
1743 else
1744 {
1745 /* Examine the list of RTEs in the Request one by one. For each
1746 entry, look up the destination in the router's routing
1747 database and, if there is a route, put that route's metric in
1748 the metric field of the RTE. If there is no explicit route
1749 to the specified destination, put infinity in the metric
1750 field. Once all the entries have been filled in, change the
1751 command from Request to Response and send the datagram back
1752 to the requestor. */
1753 p.family = AF_INET;
1754
1755 for (; ((caddr_t) rte) < lim; rte++)
1756 {
1757 p.prefix = rte->prefix;
1758 p.prefixlen = ip_masklen (rte->mask);
1759 apply_mask_ipv4 (&p);
1760
1761 rp = route_node_lookup (rip->table, (struct prefix *) &p);
1762 if (rp)
1763 {
Lu Fengb397cf42014-07-18 06:13:18 +00001764 rinfo = listgetdata (listhead ((struct list *)rp->info));
paul718e3742002-12-13 20:15:29 +00001765 rte->metric = htonl (rinfo->metric);
1766 route_unlock_node (rp);
1767 }
1768 else
1769 rte->metric = htonl (RIP_METRIC_INFINITY);
1770 }
1771 packet->command = RIP_RESPONSE;
1772
paulc49ad8f2004-10-22 10:27:28 +00001773 rip_send_packet ((u_char *)packet, size, from, ifc);
paul718e3742002-12-13 20:15:29 +00001774 }
1775 rip_global_queries++;
1776}
1777
1778#if RIP_RECVMSG
1779/* Set IPv6 packet info to the socket. */
1780static int
1781setsockopt_pktinfo (int sock)
1782{
1783 int ret;
1784 int val = 1;
1785
1786 ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
1787 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001788 zlog_warn ("Can't setsockopt IP_PKTINFO : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001789 return ret;
1790}
1791
1792/* Read RIP packet by recvmsg function. */
1793int
1794rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from,
1795 int *ifindex)
1796{
1797 int ret;
1798 struct msghdr msg;
1799 struct iovec iov;
1800 struct cmsghdr *ptr;
1801 char adata[1024];
1802
1803 msg.msg_name = (void *) from;
1804 msg.msg_namelen = sizeof (struct sockaddr_in);
1805 msg.msg_iov = &iov;
1806 msg.msg_iovlen = 1;
1807 msg.msg_control = (void *) adata;
1808 msg.msg_controllen = sizeof adata;
1809 iov.iov_base = buf;
1810 iov.iov_len = size;
1811
1812 ret = recvmsg (sock, &msg, 0);
1813 if (ret < 0)
1814 return ret;
1815
ajsb99760a2005-01-04 16:24:43 +00001816 for (ptr = ZCMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr))
paul718e3742002-12-13 20:15:29 +00001817 if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO)
1818 {
1819 struct in_pktinfo *pktinfo;
1820 int i;
1821
1822 pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr);
1823 i = pktinfo->ipi_ifindex;
1824 }
1825 return ret;
1826}
1827
1828/* RIP packet read function. */
1829int
1830rip_read_new (struct thread *t)
1831{
1832 int ret;
1833 int sock;
1834 char buf[RIP_PACKET_MAXSIZ];
1835 struct sockaddr_in from;
1836 unsigned int ifindex;
1837
1838 /* Fetch socket then register myself. */
1839 sock = THREAD_FD (t);
1840 rip_event (RIP_READ, sock);
1841
1842 /* Read RIP packet. */
1843 ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex);
1844 if (ret < 0)
1845 {
ajs6099b3b2004-11-20 02:06:59 +00001846 zlog_warn ("Can't read RIP packet: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001847 return ret;
1848 }
1849
1850 return ret;
1851}
1852#endif /* RIP_RECVMSG */
1853
1854/* First entry point of RIP packet. */
pauldc63bfd2005-10-25 23:31:05 +00001855static int
paul718e3742002-12-13 20:15:29 +00001856rip_read (struct thread *t)
1857{
1858 int sock;
1859 int ret;
1860 int rtenum;
1861 union rip_buf rip_buf;
1862 struct rip_packet *packet;
1863 struct sockaddr_in from;
paul11dde9c2004-05-31 14:00:00 +00001864 int len;
Paul Jakma3e557ae2006-09-11 02:10:40 +00001865 int vrecv;
paul11dde9c2004-05-31 14:00:00 +00001866 socklen_t fromlen;
paul718e3742002-12-13 20:15:29 +00001867 struct interface *ifp;
paulc49ad8f2004-10-22 10:27:28 +00001868 struct connected *ifc;
paul718e3742002-12-13 20:15:29 +00001869 struct rip_interface *ri;
1870
1871 /* Fetch socket then register myself. */
1872 sock = THREAD_FD (t);
1873 rip->t_read = NULL;
1874
1875 /* Add myself to tne next event */
1876 rip_event (RIP_READ, sock);
1877
1878 /* RIPd manages only IPv4. */
1879 memset (&from, 0, sizeof (struct sockaddr_in));
1880 fromlen = sizeof (struct sockaddr_in);
1881
1882 len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0,
1883 (struct sockaddr *) &from, &fromlen);
1884 if (len < 0)
1885 {
ajs6099b3b2004-11-20 02:06:59 +00001886 zlog_info ("recvfrom failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001887 return len;
1888 }
1889
1890 /* Check is this packet comming from myself? */
paul31a476c2003-09-29 19:54:53 +00001891 if (if_check_address (from.sin_addr))
paul718e3742002-12-13 20:15:29 +00001892 {
1893 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001894 zlog_debug ("ignore packet comes from myself");
paul718e3742002-12-13 20:15:29 +00001895 return -1;
1896 }
1897
1898 /* Which interface is this packet comes from. */
1899 ifp = if_lookup_address (from.sin_addr);
paulc49ad8f2004-10-22 10:27:28 +00001900
paul718e3742002-12-13 20:15:29 +00001901 /* RIP packet received */
1902 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001903 zlog_debug ("RECV packet from %s port %d on %s",
paul718e3742002-12-13 20:15:29 +00001904 inet_ntoa (from.sin_addr), ntohs (from.sin_port),
1905 ifp ? ifp->name : "unknown");
1906
1907 /* If this packet come from unknown interface, ignore it. */
1908 if (ifp == NULL)
1909 {
ajs766a0ca2004-12-15 14:55:51 +00001910 zlog_info ("rip_read: cannot find interface for packet from %s port %d",
1911 inet_ntoa(from.sin_addr), ntohs (from.sin_port));
paulc49ad8f2004-10-22 10:27:28 +00001912 return -1;
1913 }
1914
1915 ifc = connected_lookup_address (ifp, from.sin_addr);
1916
1917 if (ifc == NULL)
1918 {
ajs766a0ca2004-12-15 14:55:51 +00001919 zlog_info ("rip_read: cannot find connected address for packet from %s "
1920 "port %d on interface %s",
1921 inet_ntoa(from.sin_addr), ntohs (from.sin_port), ifp->name);
paul718e3742002-12-13 20:15:29 +00001922 return -1;
1923 }
1924
1925 /* Packet length check. */
1926 if (len < RIP_PACKET_MINSIZ)
1927 {
1928 zlog_warn ("packet size %d is smaller than minimum size %d",
1929 len, RIP_PACKET_MINSIZ);
1930 rip_peer_bad_packet (&from);
1931 return len;
1932 }
1933 if (len > RIP_PACKET_MAXSIZ)
1934 {
1935 zlog_warn ("packet size %d is larger than max size %d",
1936 len, RIP_PACKET_MAXSIZ);
1937 rip_peer_bad_packet (&from);
1938 return len;
1939 }
1940
1941 /* Packet alignment check. */
1942 if ((len - RIP_PACKET_MINSIZ) % 20)
1943 {
1944 zlog_warn ("packet size %d is wrong for RIP packet alignment", len);
1945 rip_peer_bad_packet (&from);
1946 return len;
1947 }
1948
1949 /* Set RTE number. */
1950 rtenum = ((len - RIP_PACKET_MINSIZ) / 20);
1951
1952 /* For easy to handle. */
1953 packet = &rip_buf.rip_packet;
1954
1955 /* RIP version check. */
1956 if (packet->version == 0)
1957 {
1958 zlog_info ("version 0 with command %d received.", packet->command);
1959 rip_peer_bad_packet (&from);
1960 return -1;
1961 }
1962
1963 /* Dump RIP packet. */
1964 if (IS_RIP_DEBUG_RECV)
1965 rip_packet_dump (packet, len, "RECV");
1966
1967 /* RIP version adjust. This code should rethink now. RFC1058 says
1968 that "Version 1 implementations are to ignore this extra data and
1969 process only the fields specified in this document.". So RIPv3
1970 packet should be treated as RIPv1 ignoring must be zero field. */
1971 if (packet->version > RIPv2)
1972 packet->version = RIPv2;
1973
1974 /* Is RIP running or is this RIP neighbor ?*/
1975 ri = ifp->info;
1976 if (! ri->running && ! rip_neighbor_lookup (&from))
1977 {
1978 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001979 zlog_debug ("RIP is not enabled on interface %s.", ifp->name);
paul718e3742002-12-13 20:15:29 +00001980 rip_peer_bad_packet (&from);
1981 return -1;
1982 }
1983
Paul Jakma15a2b082006-05-04 07:36:34 +00001984 /* RIP Version check. RFC2453, 4.6 and 5.1 */
Paul Jakma3e557ae2006-09-11 02:10:40 +00001985 vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ?
1986 rip->version_recv : ri->ri_receive);
Paul Jakma15a2b082006-05-04 07:36:34 +00001987 if ((packet->version == RIPv1) && !(vrecv & RIPv1))
paul718e3742002-12-13 20:15:29 +00001988 {
Paul Jakma15a2b082006-05-04 07:36:34 +00001989 if (IS_RIP_DEBUG_PACKET)
1990 zlog_debug (" packet's v%d doesn't fit to if version spec",
1991 packet->version);
1992 rip_peer_bad_packet (&from);
1993 return -1;
paul718e3742002-12-13 20:15:29 +00001994 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001995 if ((packet->version == RIPv2) && !(vrecv & RIPv2))
1996 {
1997 if (IS_RIP_DEBUG_PACKET)
1998 zlog_debug (" packet's v%d doesn't fit to if version spec",
1999 packet->version);
2000 rip_peer_bad_packet (&from);
2001 return -1;
2002 }
2003
paul718e3742002-12-13 20:15:29 +00002004 /* RFC2453 5.2 If the router is not configured to authenticate RIP-2
2005 messages, then RIP-1 and unauthenticated RIP-2 messages will be
2006 accepted; authenticated RIP-2 messages shall be discarded. */
paul718e3742002-12-13 20:15:29 +00002007 if ((ri->auth_type == RIP_NO_AUTH)
2008 && rtenum
paulca5e5162004-06-06 22:06:33 +00002009 && (packet->version == RIPv2)
2010 && (packet->rte->family == htons(RIP_FAMILY_AUTH)))
paul718e3742002-12-13 20:15:29 +00002011 {
2012 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002013 zlog_debug ("packet RIPv%d is dropped because authentication disabled",
paul718e3742002-12-13 20:15:29 +00002014 packet->version);
2015 rip_peer_bad_packet (&from);
2016 return -1;
2017 }
Paul Jakma15a2b082006-05-04 07:36:34 +00002018
2019 /* RFC:
2020 If the router is configured to authenticate RIP-2 messages, then
paul718e3742002-12-13 20:15:29 +00002021 RIP-1 messages and RIP-2 messages which pass authentication
2022 testing shall be accepted; unauthenticated and failed
2023 authentication RIP-2 messages shall be discarded. For maximum
2024 security, RIP-1 messages should be ignored when authentication is
2025 in use (see section 4.1); otherwise, the routing information from
2026 authenticated messages will be propagated by RIP-1 routers in an
Paul Jakma15a2b082006-05-04 07:36:34 +00002027 unauthenticated manner.
2028 */
2029 /* We make an exception for RIPv1 REQUEST packets, to which we'll
2030 * always reply regardless of authentication settings, because:
2031 *
2032 * - if there other authorised routers on-link, the REQUESTor can
2033 * passively obtain the routing updates anyway
2034 * - if there are no other authorised routers on-link, RIP can
2035 * easily be disabled for the link to prevent giving out information
2036 * on state of this routers RIP routing table..
2037 *
2038 * I.e. if RIPv1 has any place anymore these days, it's as a very
2039 * simple way to distribute routing information (e.g. to embedded
2040 * hosts / appliances) and the ability to give out RIPv1
2041 * routing-information freely, while still requiring RIPv2
2042 * authentication for any RESPONSEs might be vaguely useful.
2043 */
2044 if (ri->auth_type != RIP_NO_AUTH
2045 && packet->version == RIPv1)
paul718e3742002-12-13 20:15:29 +00002046 {
Paul Jakma15a2b082006-05-04 07:36:34 +00002047 /* Discard RIPv1 messages other than REQUESTs */
2048 if (packet->command != RIP_REQUEST)
2049 {
2050 if (IS_RIP_DEBUG_PACKET)
2051 zlog_debug ("RIPv1" " dropped because authentication enabled");
2052 rip_peer_bad_packet (&from);
2053 return -1;
2054 }
2055 }
2056 else if (ri->auth_type != RIP_NO_AUTH)
2057 {
2058 const char *auth_desc;
2059
2060 if (rtenum == 0)
2061 {
2062 /* There definitely is no authentication in the packet. */
2063 if (IS_RIP_DEBUG_PACKET)
2064 zlog_debug ("RIPv2 authentication failed: no auth RTE in packet");
2065 rip_peer_bad_packet (&from);
2066 return -1;
2067 }
2068
2069 /* First RTE must be an Authentication Family RTE */
2070 if (packet->rte->family != htons(RIP_FAMILY_AUTH))
2071 {
2072 if (IS_RIP_DEBUG_PACKET)
2073 zlog_debug ("RIPv2" " dropped because authentication enabled");
paul718e3742002-12-13 20:15:29 +00002074 rip_peer_bad_packet (&from);
2075 return -1;
Paul Jakma15a2b082006-05-04 07:36:34 +00002076 }
2077
paul718e3742002-12-13 20:15:29 +00002078 /* Check RIPv2 authentication. */
Paul Jakma15a2b082006-05-04 07:36:34 +00002079 switch (ntohs(packet->rte->tag))
2080 {
2081 case RIP_AUTH_SIMPLE_PASSWORD:
2082 auth_desc = "simple";
2083 ret = rip_auth_simple_password (packet->rte, &from, ifp);
2084 break;
2085
2086 case RIP_AUTH_MD5:
2087 auth_desc = "MD5";
2088 ret = rip_auth_md5 (packet, &from, len, ifp);
2089 /* Reset RIP packet length to trim MD5 data. */
2090 len = ret;
2091 break;
2092
2093 default:
2094 ret = 0;
2095 auth_desc = "unknown type";
2096 if (IS_RIP_DEBUG_PACKET)
2097 zlog_debug ("RIPv2 Unknown authentication type %d",
2098 ntohs (packet->rte->tag));
2099 }
2100
2101 if (ret)
2102 {
2103 if (IS_RIP_DEBUG_PACKET)
2104 zlog_debug ("RIPv2 %s authentication success", auth_desc);
2105 }
2106 else
2107 {
2108 if (IS_RIP_DEBUG_PACKET)
2109 zlog_debug ("RIPv2 %s authentication failure", auth_desc);
2110 rip_peer_bad_packet (&from);
2111 return -1;
2112 }
paul718e3742002-12-13 20:15:29 +00002113 }
2114
2115 /* Process each command. */
2116 switch (packet->command)
2117 {
2118 case RIP_RESPONSE:
paulc49ad8f2004-10-22 10:27:28 +00002119 rip_response_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002120 break;
2121 case RIP_REQUEST:
2122 case RIP_POLL:
paulc49ad8f2004-10-22 10:27:28 +00002123 rip_request_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002124 break;
2125 case RIP_TRACEON:
2126 case RIP_TRACEOFF:
2127 zlog_info ("Obsolete command %s received, please sent it to routed",
2128 lookup (rip_msg, packet->command));
2129 rip_peer_bad_packet (&from);
2130 break;
2131 case RIP_POLL_ENTRY:
2132 zlog_info ("Obsolete command %s received",
2133 lookup (rip_msg, packet->command));
2134 rip_peer_bad_packet (&from);
2135 break;
2136 default:
2137 zlog_info ("Unknown RIP command %d received", packet->command);
2138 rip_peer_bad_packet (&from);
2139 break;
2140 }
2141
2142 return len;
2143}
2144
paul718e3742002-12-13 20:15:29 +00002145/* Write routing table entry to the stream and return next index of
2146 the routing table entry in the stream. */
pauldc63bfd2005-10-25 23:31:05 +00002147static int
paul718e3742002-12-13 20:15:29 +00002148rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p,
paulb14ee002005-02-04 23:42:41 +00002149 u_char version, struct rip_info *rinfo)
paul718e3742002-12-13 20:15:29 +00002150{
2151 struct in_addr mask;
paul718e3742002-12-13 20:15:29 +00002152
2153 /* Write routing table entry. */
2154 if (version == RIPv1)
2155 {
2156 stream_putw (s, AF_INET);
2157 stream_putw (s, 0);
2158 stream_put_ipv4 (s, p->prefix.s_addr);
2159 stream_put_ipv4 (s, 0);
2160 stream_put_ipv4 (s, 0);
2161 stream_putl (s, rinfo->metric_out);
2162 }
2163 else
2164 {
2165 masklen2ip (p->prefixlen, &mask);
2166
2167 stream_putw (s, AF_INET);
hasso16705132003-05-25 14:49:19 +00002168 stream_putw (s, rinfo->tag_out);
paul718e3742002-12-13 20:15:29 +00002169 stream_put_ipv4 (s, p->prefix.s_addr);
2170 stream_put_ipv4 (s, mask.s_addr);
2171 stream_put_ipv4 (s, rinfo->nexthop_out.s_addr);
2172 stream_putl (s, rinfo->metric_out);
2173 }
2174
2175 return ++num;
2176}
2177
2178/* Send update to the ifp or spcified neighbor. */
2179void
paulc49ad8f2004-10-22 10:27:28 +00002180rip_output_process (struct connected *ifc, struct sockaddr_in *to,
2181 int route_type, u_char version)
paul718e3742002-12-13 20:15:29 +00002182{
2183 int ret;
2184 struct stream *s;
2185 struct route_node *rp;
2186 struct rip_info *rinfo;
2187 struct rip_interface *ri;
2188 struct prefix_ipv4 *p;
2189 struct prefix_ipv4 classfull;
paul727d1042002-12-13 20:50:29 +00002190 struct prefix_ipv4 ifaddrclass;
paulb14ee002005-02-04 23:42:41 +00002191 struct key *key = NULL;
2192 /* this might need to made dynamic if RIP ever supported auth methods
2193 with larger key string sizes */
2194 char auth_str[RIP_AUTH_SIMPLE_SIZE];
pauldc63bfd2005-10-25 23:31:05 +00002195 size_t doff = 0; /* offset of digest offset field */
paul2c61ae32005-08-16 15:22:14 +00002196 int num = 0;
paul718e3742002-12-13 20:15:29 +00002197 int rtemax;
paul01d09082003-06-08 21:22:18 +00002198 int subnetted = 0;
Lu Fengb397cf42014-07-18 06:13:18 +00002199 struct list *list = NULL;
2200 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00002201
2202 /* Logging output event. */
2203 if (IS_RIP_DEBUG_EVENT)
2204 {
2205 if (to)
ajs5d6c3772004-12-08 19:24:06 +00002206 zlog_debug ("update routes to neighbor %s", inet_ntoa (to->sin_addr));
paul718e3742002-12-13 20:15:29 +00002207 else
ajs5d6c3772004-12-08 19:24:06 +00002208 zlog_debug ("update routes on interface %s ifindex %d",
paulc49ad8f2004-10-22 10:27:28 +00002209 ifc->ifp->name, ifc->ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002210 }
2211
2212 /* Set output stream. */
2213 s = rip->obuf;
2214
2215 /* Reset stream and RTE counter. */
2216 stream_reset (s);
Lu Feng342a31b2014-06-25 07:43:15 +00002217 rtemax = RIP_MAX_RTE;
paul718e3742002-12-13 20:15:29 +00002218
2219 /* Get RIP interface. */
paulc49ad8f2004-10-22 10:27:28 +00002220 ri = ifc->ifp->info;
paul718e3742002-12-13 20:15:29 +00002221
2222 /* If output interface is in simple password authentication mode, we
2223 need space for authentication data. */
2224 if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
2225 rtemax -= 1;
2226
2227 /* If output interface is in MD5 authentication mode, we need space
2228 for authentication header and data. */
2229 if (ri->auth_type == RIP_AUTH_MD5)
2230 rtemax -= 2;
2231
2232 /* If output interface is in simple password authentication mode
2233 and string or keychain is specified we need space for auth. data */
paulb14ee002005-02-04 23:42:41 +00002234 if (ri->auth_type != RIP_NO_AUTH)
paul718e3742002-12-13 20:15:29 +00002235 {
2236 if (ri->key_chain)
2237 {
2238 struct keychain *keychain;
2239
2240 keychain = keychain_lookup (ri->key_chain);
2241 if (keychain)
paulb14ee002005-02-04 23:42:41 +00002242 key = key_lookup_for_send (keychain);
paul718e3742002-12-13 20:15:29 +00002243 }
paulb14ee002005-02-04 23:42:41 +00002244 /* to be passed to auth functions later */
2245 rip_auth_prepare_str_send (ri, key, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002246 }
2247
paul727d1042002-12-13 20:50:29 +00002248 if (version == RIPv1)
2249 {
paulc49ad8f2004-10-22 10:27:28 +00002250 memcpy (&ifaddrclass, ifc->address, sizeof (struct prefix_ipv4));
paul727d1042002-12-13 20:50:29 +00002251 apply_classful_mask_ipv4 (&ifaddrclass);
2252 subnetted = 0;
paulc49ad8f2004-10-22 10:27:28 +00002253 if (ifc->address->prefixlen > ifaddrclass.prefixlen)
paul01d09082003-06-08 21:22:18 +00002254 subnetted = 1;
paul727d1042002-12-13 20:50:29 +00002255 }
2256
paul718e3742002-12-13 20:15:29 +00002257 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002258 if ((list = rp->info) != NULL && listcount (list) != 0)
paul718e3742002-12-13 20:15:29 +00002259 {
Lu Fengb397cf42014-07-18 06:13:18 +00002260 rinfo = listgetdata (listhead (list));
paul727d1042002-12-13 20:50:29 +00002261 /* For RIPv1, if we are subnetted, output subnets in our network */
2262 /* that have the same mask as the output "interface". For other */
2263 /* networks, only the classfull version is output. */
paul718e3742002-12-13 20:15:29 +00002264
2265 if (version == RIPv1)
2266 {
paul727d1042002-12-13 20:50:29 +00002267 p = (struct prefix_ipv4 *) &rp->p;
paul718e3742002-12-13 20:15:29 +00002268
2269 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002270 zlog_debug("RIPv1 mask check, %s/%d considered for output",
paul727d1042002-12-13 20:50:29 +00002271 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002272
paul727d1042002-12-13 20:50:29 +00002273 if (subnetted &&
2274 prefix_match ((struct prefix *) &ifaddrclass, &rp->p))
2275 {
paulc49ad8f2004-10-22 10:27:28 +00002276 if ((ifc->address->prefixlen != rp->p.prefixlen) &&
paul727d1042002-12-13 20:50:29 +00002277 (rp->p.prefixlen != 32))
2278 continue;
2279 }
2280 else
2281 {
2282 memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4));
2283 apply_classful_mask_ipv4(&classfull);
2284 if (rp->p.u.prefix4.s_addr != 0 &&
2285 classfull.prefixlen != rp->p.prefixlen)
2286 continue;
2287 }
paul718e3742002-12-13 20:15:29 +00002288 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002289 zlog_debug("RIPv1 mask check, %s/%d made it through",
paul727d1042002-12-13 20:50:29 +00002290 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002291 }
2292 else
2293 p = (struct prefix_ipv4 *) &rp->p;
2294
2295 /* Apply output filters. */
2296 ret = rip_outgoing_filter (p, ri);
2297 if (ret < 0)
2298 continue;
2299
2300 /* Changed route only output. */
2301 if (route_type == rip_changed_route &&
2302 (! (rinfo->flags & RIP_RTF_CHANGED)))
2303 continue;
2304
2305 /* Split horizon. */
2306 /* if (split_horizon == rip_split_horizon) */
hasso16705132003-05-25 14:49:19 +00002307 if (ri->split_horizon == RIP_SPLIT_HORIZON)
paul718e3742002-12-13 20:15:29 +00002308 {
paul42d14d92003-11-17 09:15:18 +00002309 /*
2310 * We perform split horizon for RIP and connected route.
2311 * For rip routes, we want to suppress the route if we would
2312 * end up sending the route back on the interface that we
2313 * learned it from, with a higher metric. For connected routes,
2314 * we suppress the route if the prefix is a subset of the
2315 * source address that we are going to use for the packet
2316 * (in order to handle the case when multiple subnets are
2317 * configured on the same interface).
2318 */
Lu Fengb397cf42014-07-18 06:13:18 +00002319 int suppress = 0;
2320 struct rip_info *tmp_rinfo = NULL;
2321
2322 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
2323 if (tmp_rinfo->type == ZEBRA_ROUTE_RIP &&
2324 tmp_rinfo->ifindex == ifc->ifp->ifindex)
2325 {
2326 suppress = 1;
2327 break;
2328 }
2329
2330 if (!suppress && rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002331 prefix_match((struct prefix *)p, ifc->address))
Lu Fengb397cf42014-07-18 06:13:18 +00002332 suppress = 1;
2333
2334 if (suppress)
paul718e3742002-12-13 20:15:29 +00002335 continue;
2336 }
2337
2338 /* Preparation for route-map. */
2339 rinfo->metric_set = 0;
2340 rinfo->nexthop_out.s_addr = 0;
2341 rinfo->metric_out = rinfo->metric;
hasso16705132003-05-25 14:49:19 +00002342 rinfo->tag_out = rinfo->tag;
paulc49ad8f2004-10-22 10:27:28 +00002343 rinfo->ifindex_out = ifc->ifp->ifindex;
paul718e3742002-12-13 20:15:29 +00002344
hasso16705132003-05-25 14:49:19 +00002345 /* In order to avoid some local loops,
2346 * if the RIP route has a nexthop via this interface, keep the nexthop,
2347 * otherwise set it to 0. The nexthop should not be propagated
2348 * beyond the local broadcast/multicast area in order
2349 * to avoid an IGP multi-level recursive look-up.
2350 * see (4.4)
2351 */
paulc49ad8f2004-10-22 10:27:28 +00002352 if (rinfo->ifindex == ifc->ifp->ifindex)
paul718e3742002-12-13 20:15:29 +00002353 rinfo->nexthop_out = rinfo->nexthop;
hasso16705132003-05-25 14:49:19 +00002354
2355 /* Interface route-map */
2356 if (ri->routemap[RIP_FILTER_OUT])
2357 {
2358 ret = route_map_apply (ri->routemap[RIP_FILTER_OUT],
2359 (struct prefix *) p, RMAP_RIP,
2360 rinfo);
2361
2362 if (ret == RMAP_DENYMATCH)
2363 {
2364 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002365 zlog_debug ("RIP %s/%d is filtered by route-map out",
hasso16705132003-05-25 14:49:19 +00002366 inet_ntoa (p->prefix), p->prefixlen);
2367 continue;
2368 }
2369 }
paul718e3742002-12-13 20:15:29 +00002370
hasso16705132003-05-25 14:49:19 +00002371 /* Apply redistribute route map - continue, if deny */
paul718e3742002-12-13 20:15:29 +00002372 if (rip->route_map[rinfo->type].name
2373 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2374 {
2375 ret = route_map_apply (rip->route_map[rinfo->type].map,
2376 (struct prefix *)p, RMAP_RIP, rinfo);
2377
2378 if (ret == RMAP_DENYMATCH)
2379 {
2380 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002381 zlog_debug ("%s/%d is filtered by route-map",
paul718e3742002-12-13 20:15:29 +00002382 inet_ntoa (p->prefix), p->prefixlen);
2383 continue;
2384 }
2385 }
2386
2387 /* When route-map does not set metric. */
2388 if (! rinfo->metric_set)
2389 {
2390 /* If redistribute metric is set. */
2391 if (rip->route_map[rinfo->type].metric_config
2392 && rinfo->metric != RIP_METRIC_INFINITY)
2393 {
2394 rinfo->metric_out = rip->route_map[rinfo->type].metric;
2395 }
2396 else
2397 {
2398 /* If the route is not connected or localy generated
2399 one, use default-metric value*/
2400 if (rinfo->type != ZEBRA_ROUTE_RIP
2401 && rinfo->type != ZEBRA_ROUTE_CONNECT
2402 && rinfo->metric != RIP_METRIC_INFINITY)
2403 rinfo->metric_out = rip->default_metric;
2404 }
2405 }
2406
2407 /* Apply offset-list */
2408 if (rinfo->metric != RIP_METRIC_INFINITY)
paulc49ad8f2004-10-22 10:27:28 +00002409 rip_offset_list_apply_out (p, ifc->ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00002410
2411 if (rinfo->metric_out > RIP_METRIC_INFINITY)
2412 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002413
2414 /* Perform split-horizon with poisoned reverse
2415 * for RIP and connected routes.
2416 **/
2417 if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) {
paul42d14d92003-11-17 09:15:18 +00002418 /*
2419 * We perform split horizon for RIP and connected route.
2420 * For rip routes, we want to suppress the route if we would
2421 * end up sending the route back on the interface that we
2422 * learned it from, with a higher metric. For connected routes,
2423 * we suppress the route if the prefix is a subset of the
2424 * source address that we are going to use for the packet
2425 * (in order to handle the case when multiple subnets are
2426 * configured on the same interface).
2427 */
Lu Fengb397cf42014-07-18 06:13:18 +00002428 struct rip_info *tmp_rinfo = NULL;
2429
2430 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
2431 if (tmp_rinfo->type == ZEBRA_ROUTE_RIP &&
2432 tmp_rinfo->ifindex == ifc->ifp->ifindex)
2433 rinfo->metric_out = RIP_METRIC_INFINITY;
2434 if (tmp_rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002435 prefix_match((struct prefix *)p, ifc->address))
Lu Fengb397cf42014-07-18 06:13:18 +00002436 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002437 }
paulb14ee002005-02-04 23:42:41 +00002438
2439 /* Prepare preamble, auth headers, if needs be */
2440 if (num == 0)
2441 {
2442 stream_putc (s, RIP_RESPONSE);
2443 stream_putc (s, version);
2444 stream_putw (s, 0);
2445
paul0cb8a012005-05-29 11:27:24 +00002446 /* auth header for !v1 && !no_auth */
2447 if ( (ri->auth_type != RIP_NO_AUTH) && (version != RIPv1) )
paulb14ee002005-02-04 23:42:41 +00002448 doff = rip_auth_header_write (s, ri, key, auth_str,
2449 RIP_AUTH_SIMPLE_SIZE);
2450 }
2451
paul718e3742002-12-13 20:15:29 +00002452 /* Write RTE to the stream. */
paulb14ee002005-02-04 23:42:41 +00002453 num = rip_write_rte (num, s, p, version, rinfo);
paul718e3742002-12-13 20:15:29 +00002454 if (num == rtemax)
2455 {
2456 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002457 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002458
2459 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s),
paulc49ad8f2004-10-22 10:27:28 +00002460 to, ifc);
paul718e3742002-12-13 20:15:29 +00002461
2462 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2463 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2464 stream_get_endp(s), "SEND");
2465 num = 0;
2466 stream_reset (s);
2467 }
2468 }
2469
2470 /* Flush unwritten RTE. */
2471 if (num != 0)
2472 {
2473 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002474 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002475
paulc49ad8f2004-10-22 10:27:28 +00002476 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifc);
paul718e3742002-12-13 20:15:29 +00002477
2478 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2479 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2480 stream_get_endp (s), "SEND");
2481 num = 0;
2482 stream_reset (s);
2483 }
2484
2485 /* Statistics updates. */
2486 ri->sent_updates++;
2487}
2488
2489/* Send RIP packet to the interface. */
pauldc63bfd2005-10-25 23:31:05 +00002490static void
paulc49ad8f2004-10-22 10:27:28 +00002491rip_update_interface (struct connected *ifc, u_char version, int route_type)
paul718e3742002-12-13 20:15:29 +00002492{
paul718e3742002-12-13 20:15:29 +00002493 struct sockaddr_in to;
2494
2495 /* When RIP version is 2 and multicast enable interface. */
paulc49ad8f2004-10-22 10:27:28 +00002496 if (version == RIPv2 && if_is_multicast (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002497 {
2498 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002499 zlog_debug ("multicast announce on %s ", ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002500
paulc49ad8f2004-10-22 10:27:28 +00002501 rip_output_process (ifc, NULL, route_type, version);
paul718e3742002-12-13 20:15:29 +00002502 return;
2503 }
paulc49ad8f2004-10-22 10:27:28 +00002504
paul718e3742002-12-13 20:15:29 +00002505 /* If we can't send multicast packet, send it with unicast. */
paulc49ad8f2004-10-22 10:27:28 +00002506 if (if_is_broadcast (ifc->ifp) || if_is_pointopoint (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002507 {
paulc49ad8f2004-10-22 10:27:28 +00002508 if (ifc->address->family == AF_INET)
2509 {
2510 /* Destination address and port setting. */
2511 memset (&to, 0, sizeof (struct sockaddr_in));
2512 if (ifc->destination)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002513 /* use specified broadcast or peer destination addr */
paulc49ad8f2004-10-22 10:27:28 +00002514 to.sin_addr = ifc->destination->u.prefix4;
Andrew J. Schorre4529632006-12-12 19:18:21 +00002515 else if (ifc->address->prefixlen < IPV4_MAX_PREFIXLEN)
paulc49ad8f2004-10-22 10:27:28 +00002516 /* calculate the appropriate broadcast address */
2517 to.sin_addr.s_addr =
2518 ipv4_broadcast_addr(ifc->address->u.prefix4.s_addr,
2519 ifc->address->prefixlen);
Andrew J. Schorre4529632006-12-12 19:18:21 +00002520 else
2521 /* do not know where to send the packet */
2522 return;
paulc49ad8f2004-10-22 10:27:28 +00002523 to.sin_port = htons (RIP_PORT_DEFAULT);
paul718e3742002-12-13 20:15:29 +00002524
paulc49ad8f2004-10-22 10:27:28 +00002525 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002526 zlog_debug("%s announce to %s on %s",
2527 CONNECTED_PEER(ifc) ? "unicast" : "broadcast",
2528 inet_ntoa (to.sin_addr), ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002529
paulc49ad8f2004-10-22 10:27:28 +00002530 rip_output_process (ifc, &to, route_type, version);
2531 }
paul718e3742002-12-13 20:15:29 +00002532 }
2533}
2534
2535/* Update send to all interface and neighbor. */
pauldc63bfd2005-10-25 23:31:05 +00002536static void
paul718e3742002-12-13 20:15:29 +00002537rip_update_process (int route_type)
2538{
paul1eb8ef22005-04-07 07:30:20 +00002539 struct listnode *node;
2540 struct listnode *ifnode, *ifnnode;
paulcc1131a2003-10-15 23:20:17 +00002541 struct connected *connected;
paul718e3742002-12-13 20:15:29 +00002542 struct interface *ifp;
2543 struct rip_interface *ri;
2544 struct route_node *rp;
2545 struct sockaddr_in to;
2546 struct prefix_ipv4 *p;
2547
2548 /* Send RIP update to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00002549 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00002550 {
paul718e3742002-12-13 20:15:29 +00002551 if (if_is_loopback (ifp))
2552 continue;
2553
paul2e3b2e42002-12-13 21:03:13 +00002554 if (! if_is_operative (ifp))
paul718e3742002-12-13 20:15:29 +00002555 continue;
2556
2557 /* Fetch RIP interface information. */
2558 ri = ifp->info;
2559
2560 /* When passive interface is specified, suppress announce to the
2561 interface. */
2562 if (ri->passive)
2563 continue;
2564
2565 if (ri->running)
2566 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002567 /*
2568 * If there is no version configuration in the interface,
2569 * use rip's version setting.
2570 */
2571 int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
2572 rip->version_send : ri->ri_send);
2573
paul718e3742002-12-13 20:15:29 +00002574 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002575 zlog_debug("SEND UPDATE to %s ifindex %d",
2576 (ifp->name ? ifp->name : "_unknown_"), ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002577
paulcc1131a2003-10-15 23:20:17 +00002578 /* send update on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002579 for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002580 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002581 if (connected->address->family == AF_INET)
2582 {
2583 if (vsend & RIPv1)
2584 rip_update_interface (connected, RIPv1, route_type);
2585 if ((vsend & RIPv2) && if_is_multicast(ifp))
2586 rip_update_interface (connected, RIPv2, route_type);
2587 }
2588 }
paul718e3742002-12-13 20:15:29 +00002589 }
2590 }
2591
2592 /* RIP send updates to each neighbor. */
2593 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
2594 if (rp->info != NULL)
2595 {
2596 p = (struct prefix_ipv4 *) &rp->p;
2597
2598 ifp = if_lookup_address (p->prefix);
2599 if (! ifp)
2600 {
paulc49ad8f2004-10-22 10:27:28 +00002601 zlog_warn ("Neighbor %s doesnt have connected interface!",
paul718e3742002-12-13 20:15:29 +00002602 inet_ntoa (p->prefix));
2603 continue;
2604 }
paulc49ad8f2004-10-22 10:27:28 +00002605
2606 if ( (connected = connected_lookup_address (ifp, p->prefix)) == NULL)
2607 {
2608 zlog_warn ("Neighbor %s doesnt have connected network",
2609 inet_ntoa (p->prefix));
2610 continue;
2611 }
2612
paul718e3742002-12-13 20:15:29 +00002613 /* Set destination address and port */
2614 memset (&to, 0, sizeof (struct sockaddr_in));
2615 to.sin_addr = p->prefix;
2616 to.sin_port = htons (RIP_PORT_DEFAULT);
2617
2618 /* RIP version is rip's configuration. */
paulc49ad8f2004-10-22 10:27:28 +00002619 rip_output_process (connected, &to, route_type, rip->version_send);
paul718e3742002-12-13 20:15:29 +00002620 }
2621}
2622
2623/* RIP's periodical timer. */
pauldc63bfd2005-10-25 23:31:05 +00002624static int
paul718e3742002-12-13 20:15:29 +00002625rip_update (struct thread *t)
2626{
2627 /* Clear timer pointer. */
2628 rip->t_update = NULL;
2629
2630 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002631 zlog_debug ("update timer fire!");
paul718e3742002-12-13 20:15:29 +00002632
2633 /* Process update output. */
2634 rip_update_process (rip_all_route);
2635
2636 /* Triggered updates may be suppressed if a regular update is due by
2637 the time the triggered update would be sent. */
2638 if (rip->t_triggered_interval)
2639 {
2640 thread_cancel (rip->t_triggered_interval);
2641 rip->t_triggered_interval = NULL;
2642 }
2643 rip->trigger = 0;
2644
2645 /* Register myself. */
2646 rip_event (RIP_UPDATE_EVENT, 0);
2647
2648 return 0;
2649}
2650
2651/* Walk down the RIP routing table then clear changed flag. */
pauldc63bfd2005-10-25 23:31:05 +00002652static void
paul216565a2005-10-25 23:35:28 +00002653rip_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00002654{
2655 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00002656 struct rip_info *rinfo = NULL;
2657 struct list *list = NULL;
2658 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00002659
2660 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002661 if ((list = rp->info) != NULL)
2662 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
2663 {
2664 UNSET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
2665 /* This flag can be set only on the first entry. */
2666 break;
2667 }
paul718e3742002-12-13 20:15:29 +00002668}
2669
2670/* Triggered update interval timer. */
pauldc63bfd2005-10-25 23:31:05 +00002671static int
paul718e3742002-12-13 20:15:29 +00002672rip_triggered_interval (struct thread *t)
2673{
2674 int rip_triggered_update (struct thread *);
2675
2676 rip->t_triggered_interval = NULL;
2677
2678 if (rip->trigger)
2679 {
2680 rip->trigger = 0;
2681 rip_triggered_update (t);
2682 }
2683 return 0;
2684}
2685
2686/* Execute triggered update. */
pauldc63bfd2005-10-25 23:31:05 +00002687static int
paul718e3742002-12-13 20:15:29 +00002688rip_triggered_update (struct thread *t)
2689{
2690 int interval;
2691
2692 /* Clear thred pointer. */
2693 rip->t_triggered_update = NULL;
2694
2695 /* Cancel interval timer. */
2696 if (rip->t_triggered_interval)
2697 {
2698 thread_cancel (rip->t_triggered_interval);
2699 rip->t_triggered_interval = NULL;
2700 }
2701 rip->trigger = 0;
2702
2703 /* Logging triggered update. */
2704 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002705 zlog_debug ("triggered update!");
paul718e3742002-12-13 20:15:29 +00002706
2707 /* Split Horizon processing is done when generating triggered
2708 updates as well as normal updates (see section 2.6). */
2709 rip_update_process (rip_changed_route);
2710
2711 /* Once all of the triggered updates have been generated, the route
2712 change flags should be cleared. */
2713 rip_clear_changed_flag ();
2714
2715 /* After a triggered update is sent, a timer should be set for a
2716 random interval between 1 and 5 seconds. If other changes that
2717 would trigger updates occur before the timer expires, a single
2718 update is triggered when the timer expires. */
2719 interval = (random () % 5) + 1;
2720
2721 rip->t_triggered_interval =
2722 thread_add_timer (master, rip_triggered_interval, NULL, interval);
2723
2724 return 0;
2725}
2726
2727/* Withdraw redistributed route. */
2728void
2729rip_redistribute_withdraw (int type)
2730{
2731 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00002732 struct rip_info *rinfo = NULL;
2733 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +00002734
2735 if (!rip)
2736 return;
2737
2738 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002739 if ((list = rp->info) != NULL)
paul718e3742002-12-13 20:15:29 +00002740 {
Lu Fengb397cf42014-07-18 06:13:18 +00002741 rinfo = listgetdata (listhead (list));
paul718e3742002-12-13 20:15:29 +00002742 if (rinfo->type == type
2743 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2744 {
2745 /* Perform poisoned reverse. */
2746 rinfo->metric = RIP_METRIC_INFINITY;
2747 RIP_TIMER_ON (rinfo->t_garbage_collect,
2748 rip_garbage_collect, rip->garbage_time);
2749 RIP_TIMER_OFF (rinfo->t_timeout);
2750 rinfo->flags |= RIP_RTF_CHANGED;
2751
hasso16705132003-05-25 14:49:19 +00002752 if (IS_RIP_DEBUG_EVENT) {
2753 struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p;
2754
ajs5d6c3772004-12-08 19:24:06 +00002755 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]",
hasso16705132003-05-25 14:49:19 +00002756 inet_ntoa(p->prefix), p->prefixlen,
2757 ifindex2ifname(rinfo->ifindex));
2758 }
2759
paul718e3742002-12-13 20:15:29 +00002760 rip_event (RIP_TRIGGERED_UPDATE, 0);
2761 }
2762 }
2763}
2764
2765/* Create new RIP instance and set it to global variable. */
pauldc63bfd2005-10-25 23:31:05 +00002766static int
2767rip_create (void)
paul718e3742002-12-13 20:15:29 +00002768{
Stephen Hemminger393deb92008-08-18 14:13:29 -07002769 rip = XCALLOC (MTYPE_RIP, sizeof (struct rip));
paul718e3742002-12-13 20:15:29 +00002770
2771 /* Set initial value. */
paulf38a4712003-06-07 01:10:00 +00002772 rip->version_send = RI_RIP_VERSION_2;
2773 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002774 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
2775 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
2776 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
2777 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
2778
2779 /* Initialize RIP routig table. */
2780 rip->table = route_table_init ();
2781 rip->route = route_table_init ();
2782 rip->neighbor = route_table_init ();
2783
2784 /* Make output stream. */
2785 rip->obuf = stream_new (1500);
2786
2787 /* Make socket. */
paulf69bd9d2005-06-03 18:01:50 +00002788 rip->sock = rip_create_socket (NULL);
paul718e3742002-12-13 20:15:29 +00002789 if (rip->sock < 0)
2790 return rip->sock;
2791
2792 /* Create read and timer thread. */
2793 rip_event (RIP_READ, rip->sock);
2794 rip_event (RIP_UPDATE_EVENT, 1);
2795
2796 return 0;
2797}
2798
2799/* Sned RIP request to the destination. */
2800int
2801rip_request_send (struct sockaddr_in *to, struct interface *ifp,
paul931cd542004-01-23 15:31:42 +00002802 u_char version, struct connected *connected)
paul718e3742002-12-13 20:15:29 +00002803{
2804 struct rte *rte;
2805 struct rip_packet rip_packet;
paul1eb8ef22005-04-07 07:30:20 +00002806 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00002807
2808 memset (&rip_packet, 0, sizeof (rip_packet));
2809
2810 rip_packet.command = RIP_REQUEST;
2811 rip_packet.version = version;
2812 rte = rip_packet.rte;
2813 rte->metric = htonl (RIP_METRIC_INFINITY);
2814
paul931cd542004-01-23 15:31:42 +00002815 if (connected)
2816 {
2817 /*
2818 * connected is only sent for ripv1 case, or when
2819 * interface does not support multicast. Caller loops
2820 * over each connected address for this case.
2821 */
paul11dde9c2004-05-31 14:00:00 +00002822 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002823 to, connected) != sizeof (rip_packet))
paul931cd542004-01-23 15:31:42 +00002824 return -1;
2825 else
2826 return sizeof (rip_packet);
2827 }
2828
paulcc1131a2003-10-15 23:20:17 +00002829 /* send request on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002830 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002831 {
2832 struct prefix_ipv4 *p;
2833
2834 p = (struct prefix_ipv4 *) connected->address;
2835
2836 if (p->family != AF_INET)
2837 continue;
2838
paul11dde9c2004-05-31 14:00:00 +00002839 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002840 to, connected) != sizeof (rip_packet))
paulcc1131a2003-10-15 23:20:17 +00002841 return -1;
2842 }
2843 return sizeof (rip_packet);
paul718e3742002-12-13 20:15:29 +00002844}
David Lamparter6b0655a2014-06-04 06:53:35 +02002845
pauldc63bfd2005-10-25 23:31:05 +00002846static int
paul718e3742002-12-13 20:15:29 +00002847rip_update_jitter (unsigned long time)
2848{
paul239389b2004-05-05 14:09:37 +00002849#define JITTER_BOUND 4
2850 /* We want to get the jitter to +/- 1/JITTER_BOUND the interval.
2851 Given that, we cannot let time be less than JITTER_BOUND seconds.
2852 The RIPv2 RFC says jitter should be small compared to
2853 update_time. We consider 1/JITTER_BOUND to be small.
2854 */
2855
2856 int jitter_input = time;
2857 int jitter;
2858
2859 if (jitter_input < JITTER_BOUND)
2860 jitter_input = JITTER_BOUND;
2861
2862 jitter = (((rand () % ((jitter_input * 2) + 1)) - jitter_input));
2863
2864 return jitter/JITTER_BOUND;
paul718e3742002-12-13 20:15:29 +00002865}
2866
2867void
2868rip_event (enum rip_event event, int sock)
2869{
2870 int jitter = 0;
2871
2872 switch (event)
2873 {
2874 case RIP_READ:
2875 rip->t_read = thread_add_read (master, rip_read, NULL, sock);
2876 break;
2877 case RIP_UPDATE_EVENT:
2878 if (rip->t_update)
2879 {
2880 thread_cancel (rip->t_update);
2881 rip->t_update = NULL;
2882 }
2883 jitter = rip_update_jitter (rip->update_time);
2884 rip->t_update =
2885 thread_add_timer (master, rip_update, NULL,
2886 sock ? 2 : rip->update_time + jitter);
2887 break;
2888 case RIP_TRIGGERED_UPDATE:
2889 if (rip->t_triggered_interval)
2890 rip->trigger = 1;
2891 else if (! rip->t_triggered_update)
2892 rip->t_triggered_update =
2893 thread_add_event (master, rip_triggered_update, NULL, 0);
2894 break;
2895 default:
2896 break;
2897 }
2898}
David Lamparter6b0655a2014-06-04 06:53:35 +02002899
paul718e3742002-12-13 20:15:29 +00002900DEFUN (router_rip,
2901 router_rip_cmd,
2902 "router rip",
2903 "Enable a routing process\n"
2904 "Routing Information Protocol (RIP)\n")
2905{
2906 int ret;
2907
2908 /* If rip is not enabled before. */
2909 if (! rip)
2910 {
2911 ret = rip_create ();
2912 if (ret < 0)
2913 {
2914 zlog_info ("Can't create RIP");
2915 return CMD_WARNING;
2916 }
2917 }
2918 vty->node = RIP_NODE;
2919 vty->index = rip;
2920
2921 return CMD_SUCCESS;
2922}
2923
2924DEFUN (no_router_rip,
2925 no_router_rip_cmd,
2926 "no router rip",
2927 NO_STR
2928 "Enable a routing process\n"
2929 "Routing Information Protocol (RIP)\n")
2930{
2931 if (rip)
2932 rip_clean ();
2933 return CMD_SUCCESS;
2934}
2935
2936DEFUN (rip_version,
2937 rip_version_cmd,
2938 "version <1-2>",
2939 "Set routing protocol version\n"
2940 "version\n")
2941{
2942 int version;
2943
2944 version = atoi (argv[0]);
2945 if (version != RIPv1 && version != RIPv2)
2946 {
2947 vty_out (vty, "invalid rip version %d%s", version,
2948 VTY_NEWLINE);
2949 return CMD_WARNING;
2950 }
paulf38a4712003-06-07 01:10:00 +00002951 rip->version_send = version;
2952 rip->version_recv = version;
paul718e3742002-12-13 20:15:29 +00002953
2954 return CMD_SUCCESS;
2955}
2956
2957DEFUN (no_rip_version,
2958 no_rip_version_cmd,
2959 "no version",
2960 NO_STR
2961 "Set routing protocol version\n")
2962{
2963 /* Set RIP version to the default. */
paulf38a4712003-06-07 01:10:00 +00002964 rip->version_send = RI_RIP_VERSION_2;
2965 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002966
2967 return CMD_SUCCESS;
2968}
2969
2970ALIAS (no_rip_version,
2971 no_rip_version_val_cmd,
2972 "no version <1-2>",
2973 NO_STR
2974 "Set routing protocol version\n"
2975 "version\n")
2976
2977DEFUN (rip_route,
2978 rip_route_cmd,
2979 "route A.B.C.D/M",
2980 "RIP static route configuration\n"
2981 "IP prefix <network>/<length>\n")
2982{
2983 int ret;
2984 struct prefix_ipv4 p;
2985 struct route_node *node;
2986
2987 ret = str2prefix_ipv4 (argv[0], &p);
2988 if (ret < 0)
2989 {
2990 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2991 return CMD_WARNING;
2992 }
2993 apply_mask_ipv4 (&p);
2994
2995 /* For router rip configuration. */
2996 node = route_node_get (rip->route, (struct prefix *) &p);
2997
2998 if (node->info)
2999 {
3000 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
3001 route_unlock_node (node);
3002 return CMD_WARNING;
3003 }
3004
hasso8a676be2004-10-08 06:36:38 +00003005 node->info = (char *)"static";
paul718e3742002-12-13 20:15:29 +00003006
vincentfbf5d032005-09-29 11:25:50 +00003007 rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0);
paul718e3742002-12-13 20:15:29 +00003008
3009 return CMD_SUCCESS;
3010}
3011
3012DEFUN (no_rip_route,
3013 no_rip_route_cmd,
3014 "no route A.B.C.D/M",
3015 NO_STR
3016 "RIP static route configuration\n"
3017 "IP prefix <network>/<length>\n")
3018{
3019 int ret;
3020 struct prefix_ipv4 p;
3021 struct route_node *node;
3022
3023 ret = str2prefix_ipv4 (argv[0], &p);
3024 if (ret < 0)
3025 {
3026 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
3027 return CMD_WARNING;
3028 }
3029 apply_mask_ipv4 (&p);
3030
3031 /* For router rip configuration. */
3032 node = route_node_lookup (rip->route, (struct prefix *) &p);
3033 if (! node)
3034 {
3035 vty_out (vty, "Can't find route %s.%s", argv[0],
3036 VTY_NEWLINE);
3037 return CMD_WARNING;
3038 }
3039
3040 rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
3041 route_unlock_node (node);
3042
3043 node->info = NULL;
3044 route_unlock_node (node);
3045
3046 return CMD_SUCCESS;
3047}
3048
Stephen Hemminger2c239702009-12-10 19:16:05 +03003049#if 0
pauldc63bfd2005-10-25 23:31:05 +00003050static void
paul216565a2005-10-25 23:35:28 +00003051rip_update_default_metric (void)
paul718e3742002-12-13 20:15:29 +00003052{
3053 struct route_node *np;
Lu Fengb397cf42014-07-18 06:13:18 +00003054 struct rip_info *rinfo = NULL;
3055 struct list *list = NULL;
3056 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00003057
3058 for (np = route_top (rip->table); np; np = route_next (np))
Lu Fengb397cf42014-07-18 06:13:18 +00003059 if ((list = np->info) != NULL)
3060 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
3061 if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)
3062 rinfo->metric = rip->default_metric;
paul718e3742002-12-13 20:15:29 +00003063}
Stephen Hemminger2c239702009-12-10 19:16:05 +03003064#endif
paul718e3742002-12-13 20:15:29 +00003065
3066DEFUN (rip_default_metric,
3067 rip_default_metric_cmd,
3068 "default-metric <1-16>",
3069 "Set a metric of redistribute routes\n"
3070 "Default metric\n")
3071{
3072 if (rip)
3073 {
3074 rip->default_metric = atoi (argv[0]);
3075 /* rip_update_default_metric (); */
3076 }
3077 return CMD_SUCCESS;
3078}
3079
3080DEFUN (no_rip_default_metric,
3081 no_rip_default_metric_cmd,
3082 "no default-metric",
3083 NO_STR
3084 "Set a metric of redistribute routes\n"
3085 "Default metric\n")
3086{
3087 if (rip)
3088 {
3089 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
3090 /* rip_update_default_metric (); */
3091 }
3092 return CMD_SUCCESS;
3093}
3094
3095ALIAS (no_rip_default_metric,
3096 no_rip_default_metric_val_cmd,
3097 "no default-metric <1-16>",
3098 NO_STR
3099 "Set a metric of redistribute routes\n"
3100 "Default metric\n")
3101
3102DEFUN (rip_timers,
3103 rip_timers_cmd,
3104 "timers basic <5-2147483647> <5-2147483647> <5-2147483647>",
3105 "Adjust routing timers\n"
3106 "Basic routing protocol update timers\n"
3107 "Routing table update timer value in second. Default is 30.\n"
3108 "Routing information timeout timer. Default is 180.\n"
3109 "Garbage collection timer. Default is 120.\n")
3110{
3111 unsigned long update;
3112 unsigned long timeout;
3113 unsigned long garbage;
3114 char *endptr = NULL;
3115 unsigned long RIP_TIMER_MAX = 2147483647;
3116 unsigned long RIP_TIMER_MIN = 5;
3117
3118 update = strtoul (argv[0], &endptr, 10);
3119 if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')
3120 {
3121 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
3122 return CMD_WARNING;
3123 }
3124
3125 timeout = strtoul (argv[1], &endptr, 10);
3126 if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0')
3127 {
3128 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
3129 return CMD_WARNING;
3130 }
3131
3132 garbage = strtoul (argv[2], &endptr, 10);
3133 if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0')
3134 {
3135 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
3136 return CMD_WARNING;
3137 }
3138
3139 /* Set each timer value. */
3140 rip->update_time = update;
3141 rip->timeout_time = timeout;
3142 rip->garbage_time = garbage;
3143
3144 /* Reset update timer thread. */
3145 rip_event (RIP_UPDATE_EVENT, 0);
3146
3147 return CMD_SUCCESS;
3148}
3149
3150DEFUN (no_rip_timers,
3151 no_rip_timers_cmd,
3152 "no timers basic",
3153 NO_STR
3154 "Adjust routing timers\n"
3155 "Basic routing protocol update timers\n")
3156{
3157 /* Set each timer value to the default. */
3158 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
3159 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
3160 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
3161
3162 /* Reset update timer thread. */
3163 rip_event (RIP_UPDATE_EVENT, 0);
3164
3165 return CMD_SUCCESS;
3166}
hasso16705132003-05-25 14:49:19 +00003167
3168ALIAS (no_rip_timers,
3169 no_rip_timers_val_cmd,
3170 "no timers basic <0-65535> <0-65535> <0-65535>",
3171 NO_STR
3172 "Adjust routing timers\n"
3173 "Basic routing protocol update timers\n"
3174 "Routing table update timer value in second. Default is 30.\n"
3175 "Routing information timeout timer. Default is 180.\n"
3176 "Garbage collection timer. Default is 120.\n")
3177
David Lamparter6b0655a2014-06-04 06:53:35 +02003178
paul718e3742002-12-13 20:15:29 +00003179struct route_table *rip_distance_table;
3180
3181struct rip_distance
3182{
3183 /* Distance value for the IP source prefix. */
3184 u_char distance;
3185
3186 /* Name of the access-list to be matched. */
3187 char *access_list;
3188};
3189
pauldc63bfd2005-10-25 23:31:05 +00003190static struct rip_distance *
paul216565a2005-10-25 23:35:28 +00003191rip_distance_new (void)
paul718e3742002-12-13 20:15:29 +00003192{
Stephen Hemminger393deb92008-08-18 14:13:29 -07003193 return XCALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance));
paul718e3742002-12-13 20:15:29 +00003194}
3195
pauldc63bfd2005-10-25 23:31:05 +00003196static void
paul718e3742002-12-13 20:15:29 +00003197rip_distance_free (struct rip_distance *rdistance)
3198{
3199 XFREE (MTYPE_RIP_DISTANCE, rdistance);
3200}
3201
pauldc63bfd2005-10-25 23:31:05 +00003202static int
hasso98b718a2004-10-11 12:57:57 +00003203rip_distance_set (struct vty *vty, const char *distance_str, const char *ip_str,
3204 const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003205{
3206 int ret;
3207 struct prefix_ipv4 p;
3208 u_char distance;
3209 struct route_node *rn;
3210 struct rip_distance *rdistance;
3211
3212 ret = str2prefix_ipv4 (ip_str, &p);
3213 if (ret == 0)
3214 {
3215 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3216 return CMD_WARNING;
3217 }
3218
3219 distance = atoi (distance_str);
3220
3221 /* Get RIP distance node. */
3222 rn = route_node_get (rip_distance_table, (struct prefix *) &p);
3223 if (rn->info)
3224 {
3225 rdistance = rn->info;
3226 route_unlock_node (rn);
3227 }
3228 else
3229 {
3230 rdistance = rip_distance_new ();
3231 rn->info = rdistance;
3232 }
3233
3234 /* Set distance value. */
3235 rdistance->distance = distance;
3236
3237 /* Reset access-list configuration. */
3238 if (rdistance->access_list)
3239 {
3240 free (rdistance->access_list);
3241 rdistance->access_list = NULL;
3242 }
3243 if (access_list_str)
3244 rdistance->access_list = strdup (access_list_str);
3245
3246 return CMD_SUCCESS;
3247}
3248
pauldc63bfd2005-10-25 23:31:05 +00003249static int
hasso98b718a2004-10-11 12:57:57 +00003250rip_distance_unset (struct vty *vty, const char *distance_str,
3251 const char *ip_str, const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003252{
3253 int ret;
3254 struct prefix_ipv4 p;
paul718e3742002-12-13 20:15:29 +00003255 struct route_node *rn;
3256 struct rip_distance *rdistance;
3257
3258 ret = str2prefix_ipv4 (ip_str, &p);
3259 if (ret == 0)
3260 {
3261 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3262 return CMD_WARNING;
3263 }
3264
paul718e3742002-12-13 20:15:29 +00003265 rn = route_node_lookup (rip_distance_table, (struct prefix *)&p);
3266 if (! rn)
3267 {
3268 vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE);
3269 return CMD_WARNING;
3270 }
3271
3272 rdistance = rn->info;
3273
3274 if (rdistance->access_list)
3275 free (rdistance->access_list);
3276 rip_distance_free (rdistance);
3277
3278 rn->info = NULL;
3279 route_unlock_node (rn);
3280 route_unlock_node (rn);
3281
3282 return CMD_SUCCESS;
3283}
3284
pauldc63bfd2005-10-25 23:31:05 +00003285static void
paul216565a2005-10-25 23:35:28 +00003286rip_distance_reset (void)
paul718e3742002-12-13 20:15:29 +00003287{
3288 struct route_node *rn;
3289 struct rip_distance *rdistance;
3290
3291 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3292 if ((rdistance = rn->info) != NULL)
3293 {
3294 if (rdistance->access_list)
3295 free (rdistance->access_list);
3296 rip_distance_free (rdistance);
3297 rn->info = NULL;
3298 route_unlock_node (rn);
3299 }
3300}
3301
3302/* Apply RIP information to distance method. */
3303u_char
3304rip_distance_apply (struct rip_info *rinfo)
3305{
3306 struct route_node *rn;
3307 struct prefix_ipv4 p;
3308 struct rip_distance *rdistance;
3309 struct access_list *alist;
3310
3311 if (! rip)
3312 return 0;
3313
3314 memset (&p, 0, sizeof (struct prefix_ipv4));
3315 p.family = AF_INET;
3316 p.prefix = rinfo->from;
3317 p.prefixlen = IPV4_MAX_BITLEN;
3318
3319 /* Check source address. */
3320 rn = route_node_match (rip_distance_table, (struct prefix *) &p);
3321 if (rn)
3322 {
3323 rdistance = rn->info;
3324 route_unlock_node (rn);
3325
3326 if (rdistance->access_list)
3327 {
3328 alist = access_list_lookup (AFI_IP, rdistance->access_list);
3329 if (alist == NULL)
3330 return 0;
3331 if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY)
3332 return 0;
3333
3334 return rdistance->distance;
3335 }
3336 else
3337 return rdistance->distance;
3338 }
3339
3340 if (rip->distance)
3341 return rip->distance;
3342
3343 return 0;
3344}
3345
pauldc63bfd2005-10-25 23:31:05 +00003346static void
paul718e3742002-12-13 20:15:29 +00003347rip_distance_show (struct vty *vty)
3348{
3349 struct route_node *rn;
3350 struct rip_distance *rdistance;
3351 int header = 1;
3352 char buf[BUFSIZ];
3353
3354 vty_out (vty, " Distance: (default is %d)%s",
3355 rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT,
3356 VTY_NEWLINE);
3357
3358 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3359 if ((rdistance = rn->info) != NULL)
3360 {
3361 if (header)
3362 {
3363 vty_out (vty, " Address Distance List%s",
3364 VTY_NEWLINE);
3365 header = 0;
3366 }
3367 sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
3368 vty_out (vty, " %-20s %4d %s%s",
3369 buf, rdistance->distance,
3370 rdistance->access_list ? rdistance->access_list : "",
3371 VTY_NEWLINE);
3372 }
3373}
3374
3375DEFUN (rip_distance,
3376 rip_distance_cmd,
3377 "distance <1-255>",
3378 "Administrative distance\n"
3379 "Distance value\n")
3380{
3381 rip->distance = atoi (argv[0]);
3382 return CMD_SUCCESS;
3383}
3384
3385DEFUN (no_rip_distance,
3386 no_rip_distance_cmd,
3387 "no distance <1-255>",
3388 NO_STR
3389 "Administrative distance\n"
3390 "Distance value\n")
3391{
3392 rip->distance = 0;
3393 return CMD_SUCCESS;
3394}
3395
3396DEFUN (rip_distance_source,
3397 rip_distance_source_cmd,
3398 "distance <1-255> A.B.C.D/M",
3399 "Administrative distance\n"
3400 "Distance value\n"
3401 "IP source prefix\n")
3402{
3403 rip_distance_set (vty, argv[0], argv[1], NULL);
3404 return CMD_SUCCESS;
3405}
3406
3407DEFUN (no_rip_distance_source,
3408 no_rip_distance_source_cmd,
3409 "no distance <1-255> A.B.C.D/M",
3410 NO_STR
3411 "Administrative distance\n"
3412 "Distance value\n"
3413 "IP source prefix\n")
3414{
3415 rip_distance_unset (vty, argv[0], argv[1], NULL);
3416 return CMD_SUCCESS;
3417}
3418
3419DEFUN (rip_distance_source_access_list,
3420 rip_distance_source_access_list_cmd,
3421 "distance <1-255> A.B.C.D/M WORD",
3422 "Administrative distance\n"
3423 "Distance value\n"
3424 "IP source prefix\n"
3425 "Access list name\n")
3426{
3427 rip_distance_set (vty, argv[0], argv[1], argv[2]);
3428 return CMD_SUCCESS;
3429}
3430
3431DEFUN (no_rip_distance_source_access_list,
3432 no_rip_distance_source_access_list_cmd,
3433 "no distance <1-255> A.B.C.D/M WORD",
3434 NO_STR
3435 "Administrative distance\n"
3436 "Distance value\n"
3437 "IP source prefix\n"
3438 "Access list name\n")
3439{
3440 rip_distance_unset (vty, argv[0], argv[1], argv[2]);
3441 return CMD_SUCCESS;
3442}
David Lamparter6b0655a2014-06-04 06:53:35 +02003443
Lu Feng0b74a0a2014-07-18 06:13:19 +00003444/* Update ECMP routes to zebra when ECMP is disabled. */
3445static void
3446rip_ecmp_disable (void)
3447{
3448 struct route_node *rp;
3449 struct rip_info *rinfo, *tmp_rinfo;
3450 struct list *list;
3451 struct listnode *node, *nextnode;
3452
3453 if (!rip)
3454 return;
3455
3456 for (rp = route_top (rip->table); rp; rp = route_next (rp))
3457 if ((list = rp->info) != NULL && listcount (list) > 1)
3458 {
3459 rinfo = listgetdata (listhead (list));
3460 if (!rip_route_rte (rinfo))
3461 continue;
3462
3463 /* Drop all other entries, except the first one. */
3464 for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
3465 if (tmp_rinfo != rinfo)
3466 {
3467 RIP_TIMER_OFF (tmp_rinfo->t_timeout);
3468 RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect);
3469 list_delete_node (list, node);
3470 rip_info_free (tmp_rinfo);
3471 }
3472
3473 /* Update zebra. */
3474 rip_zebra_ipv4_add (rp);
3475
3476 /* Set the route change flag. */
3477 SET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
3478
3479 /* Signal the output process to trigger an update. */
3480 rip_event (RIP_TRIGGERED_UPDATE, 0);
3481 }
3482}
3483
3484DEFUN (rip_allow_ecmp,
3485 rip_allow_ecmp_cmd,
3486 "allow-ecmp",
3487 "Allow Equal Cost MultiPath\n")
3488{
3489 if (rip->ecmp)
3490 {
3491 vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE);
3492 return CMD_WARNING;
3493 }
3494
3495 rip->ecmp = 1;
3496 zlog_info ("ECMP is enabled.");
3497 return CMD_SUCCESS;
3498}
3499
3500DEFUN (no_rip_allow_ecmp,
3501 no_rip_allow_ecmp_cmd,
3502 "no allow-ecmp",
3503 NO_STR
3504 "Allow Equal Cost MultiPath\n")
3505{
3506 if (!rip->ecmp)
3507 {
3508 vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE);
3509 return CMD_WARNING;
3510 }
3511
3512 rip->ecmp = 0;
3513 zlog_info ("ECMP is disabled.");
3514 rip_ecmp_disable ();
3515 return CMD_SUCCESS;
3516}
3517
paul718e3742002-12-13 20:15:29 +00003518/* Print out routes update time. */
pauldc63bfd2005-10-25 23:31:05 +00003519static void
paul718e3742002-12-13 20:15:29 +00003520rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo)
3521{
paul718e3742002-12-13 20:15:29 +00003522 time_t clock;
3523 struct tm *tm;
3524#define TIME_BUF 25
3525 char timebuf [TIME_BUF];
3526 struct thread *thread;
3527
paul718e3742002-12-13 20:15:29 +00003528 if ((thread = rinfo->t_timeout) != NULL)
3529 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003530 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003531 tm = gmtime (&clock);
3532 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3533 vty_out (vty, "%5s", timebuf);
3534 }
3535 else if ((thread = rinfo->t_garbage_collect) != NULL)
3536 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003537 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003538 tm = gmtime (&clock);
3539 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3540 vty_out (vty, "%5s", timebuf);
3541 }
3542}
3543
pauldc63bfd2005-10-25 23:31:05 +00003544static const char *
paul718e3742002-12-13 20:15:29 +00003545rip_route_type_print (int sub_type)
3546{
3547 switch (sub_type)
3548 {
3549 case RIP_ROUTE_RTE:
3550 return "n";
3551 case RIP_ROUTE_STATIC:
3552 return "s";
3553 case RIP_ROUTE_DEFAULT:
3554 return "d";
3555 case RIP_ROUTE_REDISTRIBUTE:
3556 return "r";
3557 case RIP_ROUTE_INTERFACE:
3558 return "i";
3559 default:
3560 return "?";
3561 }
3562}
3563
3564DEFUN (show_ip_rip,
3565 show_ip_rip_cmd,
3566 "show ip rip",
3567 SHOW_STR
3568 IP_STR
3569 "Show RIP routes\n")
3570{
3571 struct route_node *np;
Lu Fengb397cf42014-07-18 06:13:18 +00003572 struct rip_info *rinfo = NULL;
3573 struct list *list = NULL;
3574 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00003575
3576 if (! rip)
3577 return CMD_SUCCESS;
3578
hasso16705132003-05-25 14:49:19 +00003579 vty_out (vty, "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s"
3580 "Sub-codes:%s"
3581 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
paul718e3742002-12-13 20:15:29 +00003582 " (i) - interface%s%s"
hassoa1455d82004-03-03 19:36:24 +00003583 " Network Next Hop Metric From Tag Time%s",
hasso16705132003-05-25 14:49:19 +00003584 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003585
3586 for (np = route_top (rip->table); np; np = route_next (np))
Lu Fengb397cf42014-07-18 06:13:18 +00003587 if ((list = np->info) != NULL)
3588 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
paul718e3742002-12-13 20:15:29 +00003589 {
3590 int len;
3591
ajsf52d13c2005-10-01 17:38:06 +00003592 len = vty_out (vty, "%c(%s) %s/%d",
paul718e3742002-12-13 20:15:29 +00003593 /* np->lock, For debugging. */
ajsf52d13c2005-10-01 17:38:06 +00003594 zebra_route_char(rinfo->type),
paul718e3742002-12-13 20:15:29 +00003595 rip_route_type_print (rinfo->sub_type),
3596 inet_ntoa (np->p.u.prefix4), np->p.prefixlen);
3597
hassoa1455d82004-03-03 19:36:24 +00003598 len = 24 - len;
paul718e3742002-12-13 20:15:29 +00003599
3600 if (len > 0)
3601 vty_out (vty, "%*s", len, " ");
3602
3603 if (rinfo->nexthop.s_addr)
3604 vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop),
3605 rinfo->metric);
3606 else
3607 vty_out (vty, "0.0.0.0 %2d ", rinfo->metric);
3608
3609 /* Route which exist in kernel routing table. */
3610 if ((rinfo->type == ZEBRA_ROUTE_RIP) &&
3611 (rinfo->sub_type == RIP_ROUTE_RTE))
3612 {
3613 vty_out (vty, "%-15s ", inet_ntoa (rinfo->from));
hasso16705132003-05-25 14:49:19 +00003614 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003615 rip_vty_out_uptime (vty, rinfo);
3616 }
3617 else if (rinfo->metric == RIP_METRIC_INFINITY)
3618 {
3619 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003620 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003621 rip_vty_out_uptime (vty, rinfo);
3622 }
3623 else
hasso16705132003-05-25 14:49:19 +00003624 {
vincentfbf5d032005-09-29 11:25:50 +00003625 if (rinfo->external_metric)
3626 {
3627 len = vty_out (vty, "self (%s:%d)",
ajsf52d13c2005-10-01 17:38:06 +00003628 zebra_route_string(rinfo->type),
vincentfbf5d032005-09-29 11:25:50 +00003629 rinfo->external_metric);
3630 len = 16 - len;
3631 if (len > 0)
3632 vty_out (vty, "%*s", len, " ");
3633 }
3634 else
3635 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003636 vty_out (vty, "%3d", rinfo->tag);
3637 }
paul718e3742002-12-13 20:15:29 +00003638
3639 vty_out (vty, "%s", VTY_NEWLINE);
3640 }
3641 return CMD_SUCCESS;
3642}
3643
hasso16705132003-05-25 14:49:19 +00003644/* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */
3645DEFUN (show_ip_rip_status,
3646 show_ip_rip_status_cmd,
3647 "show ip rip status",
paul718e3742002-12-13 20:15:29 +00003648 SHOW_STR
3649 IP_STR
hasso16705132003-05-25 14:49:19 +00003650 "Show RIP routes\n"
paul718e3742002-12-13 20:15:29 +00003651 "IP routing protocol process parameters and statistics\n")
3652{
hasso52dc7ee2004-09-23 19:18:23 +00003653 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00003654 struct interface *ifp;
3655 struct rip_interface *ri;
Stephen Hemminger1423c802008-08-14 17:59:25 +01003656 extern const struct message ri_version_msg[];
hasso8a676be2004-10-08 06:36:38 +00003657 const char *send_version;
3658 const char *receive_version;
paul718e3742002-12-13 20:15:29 +00003659
3660 if (! rip)
3661 return CMD_SUCCESS;
3662
3663 vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE);
3664 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
3665 rip->update_time);
Andrew J. Schorra4c64822007-03-21 18:57:38 +00003666 vty_out (vty, " next due in %lu seconds%s",
3667 thread_timer_remain_second(rip->t_update),
paul718e3742002-12-13 20:15:29 +00003668 VTY_NEWLINE);
3669 vty_out (vty, " Timeout after %ld seconds,", rip->timeout_time);
3670 vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time,
3671 VTY_NEWLINE);
3672
3673 /* Filtering status show. */
3674 config_show_distribute (vty);
3675
3676 /* Default metric information. */
3677 vty_out (vty, " Default redistribution metric is %d%s",
3678 rip->default_metric, VTY_NEWLINE);
3679
3680 /* Redistribute information. */
3681 vty_out (vty, " Redistributing:");
3682 config_write_rip_redistribute (vty, 0);
3683 vty_out (vty, "%s", VTY_NEWLINE);
3684
paulf38a4712003-06-07 01:10:00 +00003685 vty_out (vty, " Default version control: send version %s,",
3686 lookup(ri_version_msg,rip->version_send));
3687 if (rip->version_recv == RI_RIP_VERSION_1_AND_2)
3688 vty_out (vty, " receive any version %s", VTY_NEWLINE);
3689 else
3690 vty_out (vty, " receive version %s %s",
3691 lookup(ri_version_msg,rip->version_recv), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003692
3693 vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE);
3694
paul1eb8ef22005-04-07 07:30:20 +00003695 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00003696 {
paul718e3742002-12-13 20:15:29 +00003697 ri = ifp->info;
3698
Stephen Hemminger82f5ee12009-04-07 15:00:46 -07003699 if (!ri->running)
3700 continue;
3701
paul718e3742002-12-13 20:15:29 +00003702 if (ri->enable_network || ri->enable_interface)
3703 {
3704 if (ri->ri_send == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003705 send_version = lookup (ri_version_msg, rip->version_send);
paul718e3742002-12-13 20:15:29 +00003706 else
3707 send_version = lookup (ri_version_msg, ri->ri_send);
3708
3709 if (ri->ri_receive == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003710 receive_version = lookup (ri_version_msg, rip->version_recv);
paul718e3742002-12-13 20:15:29 +00003711 else
3712 receive_version = lookup (ri_version_msg, ri->ri_receive);
3713
3714 vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name,
3715 send_version,
3716 receive_version,
3717 ri->key_chain ? ri->key_chain : "",
3718 VTY_NEWLINE);
3719 }
3720 }
3721
3722 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
3723 config_write_rip_network (vty, 0);
3724
paul4aaff3f2003-06-07 01:04:45 +00003725 {
3726 int found_passive = 0;
paul1eb8ef22005-04-07 07:30:20 +00003727 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul4aaff3f2003-06-07 01:04:45 +00003728 {
paul4aaff3f2003-06-07 01:04:45 +00003729 ri = ifp->info;
3730
3731 if ((ri->enable_network || ri->enable_interface) && ri->passive)
3732 {
3733 if (!found_passive)
3734 {
3735 vty_out (vty, " Passive Interface(s):%s", VTY_NEWLINE);
3736 found_passive = 1;
3737 }
3738 vty_out (vty, " %s%s", ifp->name, VTY_NEWLINE);
3739 }
3740 }
3741 }
3742
paul718e3742002-12-13 20:15:29 +00003743 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
3744 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
3745 rip_peer_display (vty);
3746
3747 rip_distance_show (vty);
3748
3749 return CMD_SUCCESS;
3750}
3751
3752/* RIP configuration write function. */
pauldc63bfd2005-10-25 23:31:05 +00003753static int
paul718e3742002-12-13 20:15:29 +00003754config_write_rip (struct vty *vty)
3755{
3756 int write = 0;
3757 struct route_node *rn;
3758 struct rip_distance *rdistance;
3759
3760 if (rip)
3761 {
3762 /* Router RIP statement. */
3763 vty_out (vty, "router rip%s", VTY_NEWLINE);
3764 write++;
3765
3766 /* RIP version statement. Default is RIP version 2. */
paulf38a4712003-06-07 01:10:00 +00003767 if (rip->version_send != RI_RIP_VERSION_2
3768 || rip->version_recv != RI_RIP_VERSION_1_AND_2)
3769 vty_out (vty, " version %d%s", rip->version_send,
paul718e3742002-12-13 20:15:29 +00003770 VTY_NEWLINE);
3771
3772 /* RIP timer configuration. */
3773 if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT
3774 || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT
3775 || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT)
3776 vty_out (vty, " timers basic %lu %lu %lu%s",
3777 rip->update_time,
3778 rip->timeout_time,
3779 rip->garbage_time,
3780 VTY_NEWLINE);
3781
3782 /* Default information configuration. */
3783 if (rip->default_information)
3784 {
3785 if (rip->default_information_route_map)
3786 vty_out (vty, " default-information originate route-map %s%s",
3787 rip->default_information_route_map, VTY_NEWLINE);
3788 else
3789 vty_out (vty, " default-information originate%s",
3790 VTY_NEWLINE);
3791 }
3792
3793 /* Redistribute configuration. */
3794 config_write_rip_redistribute (vty, 1);
3795
3796 /* RIP offset-list configuration. */
3797 config_write_rip_offset_list (vty);
3798
3799 /* RIP enabled network and interface configuration. */
3800 config_write_rip_network (vty, 1);
3801
3802 /* RIP default metric configuration */
3803 if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT)
3804 vty_out (vty, " default-metric %d%s",
3805 rip->default_metric, VTY_NEWLINE);
3806
3807 /* Distribute configuration. */
3808 write += config_write_distribute (vty);
3809
hasso16705132003-05-25 14:49:19 +00003810 /* Interface routemap configuration */
3811 write += config_write_if_rmap (vty);
3812
paul718e3742002-12-13 20:15:29 +00003813 /* Distance configuration. */
3814 if (rip->distance)
3815 vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE);
3816
3817 /* RIP source IP prefix distance configuration. */
3818 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3819 if ((rdistance = rn->info) != NULL)
3820 vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance,
3821 inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
3822 rdistance->access_list ? rdistance->access_list : "",
3823 VTY_NEWLINE);
3824
Lu Feng0b74a0a2014-07-18 06:13:19 +00003825 /* ECMP configuration. */
3826 if (rip->ecmp)
3827 vty_out (vty, " allow-ecmp%s", VTY_NEWLINE);
3828
paul718e3742002-12-13 20:15:29 +00003829 /* RIP static route configuration. */
3830 for (rn = route_top (rip->route); rn; rn = route_next (rn))
3831 if (rn->info)
3832 vty_out (vty, " route %s/%d%s",
3833 inet_ntoa (rn->p.u.prefix4),
3834 rn->p.prefixlen,
3835 VTY_NEWLINE);
3836
3837 }
3838 return write;
3839}
3840
3841/* RIP node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -08003842static struct cmd_node rip_node =
paul718e3742002-12-13 20:15:29 +00003843{
3844 RIP_NODE,
3845 "%s(config-router)# ",
3846 1
3847};
David Lamparter6b0655a2014-06-04 06:53:35 +02003848
paul718e3742002-12-13 20:15:29 +00003849/* Distribute-list update functions. */
pauldc63bfd2005-10-25 23:31:05 +00003850static void
paul718e3742002-12-13 20:15:29 +00003851rip_distribute_update (struct distribute *dist)
3852{
3853 struct interface *ifp;
3854 struct rip_interface *ri;
3855 struct access_list *alist;
3856 struct prefix_list *plist;
3857
3858 if (! dist->ifname)
3859 return;
3860
3861 ifp = if_lookup_by_name (dist->ifname);
3862 if (ifp == NULL)
3863 return;
3864
3865 ri = ifp->info;
3866
3867 if (dist->list[DISTRIBUTE_IN])
3868 {
3869 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
3870 if (alist)
3871 ri->list[RIP_FILTER_IN] = alist;
3872 else
3873 ri->list[RIP_FILTER_IN] = NULL;
3874 }
3875 else
3876 ri->list[RIP_FILTER_IN] = NULL;
3877
3878 if (dist->list[DISTRIBUTE_OUT])
3879 {
3880 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
3881 if (alist)
3882 ri->list[RIP_FILTER_OUT] = alist;
3883 else
3884 ri->list[RIP_FILTER_OUT] = NULL;
3885 }
3886 else
3887 ri->list[RIP_FILTER_OUT] = NULL;
3888
3889 if (dist->prefix[DISTRIBUTE_IN])
3890 {
3891 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
3892 if (plist)
3893 ri->prefix[RIP_FILTER_IN] = plist;
3894 else
3895 ri->prefix[RIP_FILTER_IN] = NULL;
3896 }
3897 else
3898 ri->prefix[RIP_FILTER_IN] = NULL;
3899
3900 if (dist->prefix[DISTRIBUTE_OUT])
3901 {
3902 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
3903 if (plist)
3904 ri->prefix[RIP_FILTER_OUT] = plist;
3905 else
3906 ri->prefix[RIP_FILTER_OUT] = NULL;
3907 }
3908 else
3909 ri->prefix[RIP_FILTER_OUT] = NULL;
3910}
3911
3912void
3913rip_distribute_update_interface (struct interface *ifp)
3914{
3915 struct distribute *dist;
3916
3917 dist = distribute_lookup (ifp->name);
3918 if (dist)
3919 rip_distribute_update (dist);
3920}
3921
3922/* Update all interface's distribute list. */
paul02ff83c2004-06-11 11:27:03 +00003923/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003924static void
paul02ff83c2004-06-11 11:27:03 +00003925rip_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00003926{
3927 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003928 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00003929
paul1eb8ef22005-04-07 07:30:20 +00003930 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3931 rip_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00003932}
paul11dde9c2004-05-31 14:00:00 +00003933/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003934static void
paul11dde9c2004-05-31 14:00:00 +00003935rip_distribute_update_all_wrapper(struct access_list *notused)
3936{
paul02ff83c2004-06-11 11:27:03 +00003937 rip_distribute_update_all(NULL);
paul11dde9c2004-05-31 14:00:00 +00003938}
David Lamparter6b0655a2014-06-04 06:53:35 +02003939
paul718e3742002-12-13 20:15:29 +00003940/* Delete all added rip route. */
3941void
paul216565a2005-10-25 23:35:28 +00003942rip_clean (void)
paul718e3742002-12-13 20:15:29 +00003943{
3944 int i;
3945 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00003946 struct rip_info *rinfo = NULL;
3947 struct list *list = NULL;
3948 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00003949
3950 if (rip)
3951 {
3952 /* Clear RIP routes */
3953 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00003954 if ((list = rp->info) != NULL)
3955 {
3956 rinfo = listgetdata (listhead (list));
3957 if (rip_route_rte (rinfo))
3958 rip_zebra_ipv4_delete (rp);
paul718e3742002-12-13 20:15:29 +00003959
Lu Fengb397cf42014-07-18 06:13:18 +00003960 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
3961 {
3962 RIP_TIMER_OFF (rinfo->t_timeout);
3963 RIP_TIMER_OFF (rinfo->t_garbage_collect);
3964 rip_info_free (rinfo);
3965 }
3966 list_delete (list);
3967 rp->info = NULL;
3968 route_unlock_node (rp);
3969 }
paul718e3742002-12-13 20:15:29 +00003970
3971 /* Cancel RIP related timers. */
3972 RIP_TIMER_OFF (rip->t_update);
3973 RIP_TIMER_OFF (rip->t_triggered_update);
3974 RIP_TIMER_OFF (rip->t_triggered_interval);
3975
3976 /* Cancel read thread. */
3977 if (rip->t_read)
3978 {
3979 thread_cancel (rip->t_read);
3980 rip->t_read = NULL;
3981 }
3982
3983 /* Close RIP socket. */
3984 if (rip->sock >= 0)
3985 {
3986 close (rip->sock);
3987 rip->sock = -1;
3988 }
3989
3990 /* Static RIP route configuration. */
3991 for (rp = route_top (rip->route); rp; rp = route_next (rp))
3992 if (rp->info)
3993 {
3994 rp->info = NULL;
3995 route_unlock_node (rp);
3996 }
3997
3998 /* RIP neighbor configuration. */
3999 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
4000 if (rp->info)
4001 {
4002 rp->info = NULL;
4003 route_unlock_node (rp);
4004 }
4005
4006 /* Redistribute related clear. */
4007 if (rip->default_information_route_map)
4008 free (rip->default_information_route_map);
4009
4010 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
4011 if (rip->route_map[i].name)
4012 free (rip->route_map[i].name);
4013
4014 XFREE (MTYPE_ROUTE_TABLE, rip->table);
4015 XFREE (MTYPE_ROUTE_TABLE, rip->route);
4016 XFREE (MTYPE_ROUTE_TABLE, rip->neighbor);
4017
4018 XFREE (MTYPE_RIP, rip);
4019 rip = NULL;
4020 }
4021
4022 rip_clean_network ();
paul4aaff3f2003-06-07 01:04:45 +00004023 rip_passive_nondefault_clean ();
paul718e3742002-12-13 20:15:29 +00004024 rip_offset_clean ();
4025 rip_interface_clean ();
4026 rip_distance_reset ();
4027 rip_redistribute_clean ();
4028}
4029
4030/* Reset all values to the default settings. */
4031void
paul216565a2005-10-25 23:35:28 +00004032rip_reset (void)
paul718e3742002-12-13 20:15:29 +00004033{
4034 /* Reset global counters. */
4035 rip_global_route_changes = 0;
4036 rip_global_queries = 0;
4037
4038 /* Call ripd related reset functions. */
4039 rip_debug_reset ();
4040 rip_route_map_reset ();
4041
4042 /* Call library reset functions. */
4043 vty_reset ();
4044 access_list_reset ();
4045 prefix_list_reset ();
4046
4047 distribute_list_reset ();
4048
4049 rip_interface_reset ();
4050 rip_distance_reset ();
4051
4052 rip_zclient_reset ();
4053}
4054
pauldc63bfd2005-10-25 23:31:05 +00004055static void
hasso16705132003-05-25 14:49:19 +00004056rip_if_rmap_update (struct if_rmap *if_rmap)
4057{
4058 struct interface *ifp;
4059 struct rip_interface *ri;
4060 struct route_map *rmap;
4061
4062 ifp = if_lookup_by_name (if_rmap->ifname);
4063 if (ifp == NULL)
4064 return;
4065
4066 ri = ifp->info;
4067
4068 if (if_rmap->routemap[IF_RMAP_IN])
4069 {
4070 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
4071 if (rmap)
4072 ri->routemap[IF_RMAP_IN] = rmap;
4073 else
4074 ri->routemap[IF_RMAP_IN] = NULL;
4075 }
4076 else
4077 ri->routemap[RIP_FILTER_IN] = NULL;
4078
4079 if (if_rmap->routemap[IF_RMAP_OUT])
4080 {
4081 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
4082 if (rmap)
4083 ri->routemap[IF_RMAP_OUT] = rmap;
4084 else
4085 ri->routemap[IF_RMAP_OUT] = NULL;
4086 }
4087 else
4088 ri->routemap[RIP_FILTER_OUT] = NULL;
4089}
4090
4091void
4092rip_if_rmap_update_interface (struct interface *ifp)
4093{
4094 struct if_rmap *if_rmap;
4095
4096 if_rmap = if_rmap_lookup (ifp->name);
4097 if (if_rmap)
4098 rip_if_rmap_update (if_rmap);
4099}
4100
pauldc63bfd2005-10-25 23:31:05 +00004101static void
hasso16705132003-05-25 14:49:19 +00004102rip_routemap_update_redistribute (void)
4103{
4104 int i;
4105
4106 if (rip)
4107 {
4108 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
4109 {
4110 if (rip->route_map[i].name)
4111 rip->route_map[i].map =
4112 route_map_lookup_by_name (rip->route_map[i].name);
4113 }
4114 }
4115}
4116
paul11dde9c2004-05-31 14:00:00 +00004117/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00004118static void
hasso98b718a2004-10-11 12:57:57 +00004119rip_routemap_update (const char *notused)
hasso16705132003-05-25 14:49:19 +00004120{
4121 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00004122 struct listnode *node, *nnode;
hasso16705132003-05-25 14:49:19 +00004123
paul1eb8ef22005-04-07 07:30:20 +00004124 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
4125 rip_if_rmap_update_interface (ifp);
hasso16705132003-05-25 14:49:19 +00004126
4127 rip_routemap_update_redistribute ();
4128}
4129
paul718e3742002-12-13 20:15:29 +00004130/* Allocate new rip structure and set default value. */
4131void
pauldc63bfd2005-10-25 23:31:05 +00004132rip_init (void)
paul718e3742002-12-13 20:15:29 +00004133{
4134 /* Randomize for triggered update random(). */
4135 srand (time (NULL));
4136
4137 /* Install top nodes. */
4138 install_node (&rip_node, config_write_rip);
4139
4140 /* Install rip commands. */
4141 install_element (VIEW_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00004142 install_element (VIEW_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00004143 install_element (ENABLE_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00004144 install_element (ENABLE_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00004145 install_element (CONFIG_NODE, &router_rip_cmd);
4146 install_element (CONFIG_NODE, &no_router_rip_cmd);
4147
4148 install_default (RIP_NODE);
4149 install_element (RIP_NODE, &rip_version_cmd);
4150 install_element (RIP_NODE, &no_rip_version_cmd);
4151 install_element (RIP_NODE, &no_rip_version_val_cmd);
4152 install_element (RIP_NODE, &rip_default_metric_cmd);
4153 install_element (RIP_NODE, &no_rip_default_metric_cmd);
4154 install_element (RIP_NODE, &no_rip_default_metric_val_cmd);
4155 install_element (RIP_NODE, &rip_timers_cmd);
4156 install_element (RIP_NODE, &no_rip_timers_cmd);
hasso16705132003-05-25 14:49:19 +00004157 install_element (RIP_NODE, &no_rip_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00004158 install_element (RIP_NODE, &rip_route_cmd);
4159 install_element (RIP_NODE, &no_rip_route_cmd);
4160 install_element (RIP_NODE, &rip_distance_cmd);
4161 install_element (RIP_NODE, &no_rip_distance_cmd);
4162 install_element (RIP_NODE, &rip_distance_source_cmd);
4163 install_element (RIP_NODE, &no_rip_distance_source_cmd);
4164 install_element (RIP_NODE, &rip_distance_source_access_list_cmd);
4165 install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd);
Lu Feng0b74a0a2014-07-18 06:13:19 +00004166 install_element (RIP_NODE, &rip_allow_ecmp_cmd);
4167 install_element (RIP_NODE, &no_rip_allow_ecmp_cmd);
paul718e3742002-12-13 20:15:29 +00004168
4169 /* Debug related init. */
4170 rip_debug_init ();
4171
paul718e3742002-12-13 20:15:29 +00004172 /* SNMP init. */
4173#ifdef HAVE_SNMP
4174 rip_snmp_init ();
4175#endif /* HAVE_SNMP */
4176
4177 /* Access list install. */
4178 access_list_init ();
paul11dde9c2004-05-31 14:00:00 +00004179 access_list_add_hook (rip_distribute_update_all_wrapper);
4180 access_list_delete_hook (rip_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00004181
4182 /* Prefix list initialize.*/
4183 prefix_list_init ();
4184 prefix_list_add_hook (rip_distribute_update_all);
4185 prefix_list_delete_hook (rip_distribute_update_all);
4186
4187 /* Distribute list install. */
4188 distribute_list_init (RIP_NODE);
4189 distribute_list_add_hook (rip_distribute_update);
4190 distribute_list_delete_hook (rip_distribute_update);
4191
hasso16705132003-05-25 14:49:19 +00004192 /* Route-map */
4193 rip_route_map_init ();
4194 rip_offset_init ();
4195
4196 route_map_add_hook (rip_routemap_update);
4197 route_map_delete_hook (rip_routemap_update);
4198
4199 if_rmap_init (RIP_NODE);
4200 if_rmap_hook_add (rip_if_rmap_update);
4201 if_rmap_hook_delete (rip_if_rmap_update);
4202
paul718e3742002-12-13 20:15:29 +00004203 /* Distance control. */
4204 rip_distance_table = route_table_init ();
4205}