blob: c69ef7fc6314dc59cbcf3637c8576153e51cfdf3 [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 {
paulcc1131a2003-10-15 23:20:17 +00001740 struct prefix_ipv4 saddr;
1741
1742 /* saddr will be used for determining which routes to split-horizon.
1743 Since the source address we'll pick will be on the same subnet as the
1744 destination, for the purpose of split-horizoning, we'll
1745 pretend that "from" is our source address. */
1746 saddr.family = AF_INET;
1747 saddr.prefixlen = IPV4_MAX_BITLEN;
1748 saddr.prefix = from->sin_addr;
1749
paul718e3742002-12-13 20:15:29 +00001750 /* All route with split horizon */
paulc49ad8f2004-10-22 10:27:28 +00001751 rip_output_process (ifc, from, rip_all_route, packet->version);
paul718e3742002-12-13 20:15:29 +00001752 }
1753 else
1754 {
1755 /* Examine the list of RTEs in the Request one by one. For each
1756 entry, look up the destination in the router's routing
1757 database and, if there is a route, put that route's metric in
1758 the metric field of the RTE. If there is no explicit route
1759 to the specified destination, put infinity in the metric
1760 field. Once all the entries have been filled in, change the
1761 command from Request to Response and send the datagram back
1762 to the requestor. */
1763 p.family = AF_INET;
1764
1765 for (; ((caddr_t) rte) < lim; rte++)
1766 {
1767 p.prefix = rte->prefix;
1768 p.prefixlen = ip_masklen (rte->mask);
1769 apply_mask_ipv4 (&p);
1770
1771 rp = route_node_lookup (rip->table, (struct prefix *) &p);
1772 if (rp)
1773 {
Lu Fengb397cf42014-07-18 06:13:18 +00001774 rinfo = listgetdata (listhead ((struct list *)rp->info));
paul718e3742002-12-13 20:15:29 +00001775 rte->metric = htonl (rinfo->metric);
1776 route_unlock_node (rp);
1777 }
1778 else
1779 rte->metric = htonl (RIP_METRIC_INFINITY);
1780 }
1781 packet->command = RIP_RESPONSE;
1782
paulc49ad8f2004-10-22 10:27:28 +00001783 rip_send_packet ((u_char *)packet, size, from, ifc);
paul718e3742002-12-13 20:15:29 +00001784 }
1785 rip_global_queries++;
1786}
1787
1788#if RIP_RECVMSG
1789/* Set IPv6 packet info to the socket. */
1790static int
1791setsockopt_pktinfo (int sock)
1792{
1793 int ret;
1794 int val = 1;
1795
1796 ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
1797 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001798 zlog_warn ("Can't setsockopt IP_PKTINFO : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001799 return ret;
1800}
1801
1802/* Read RIP packet by recvmsg function. */
1803int
1804rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from,
1805 int *ifindex)
1806{
1807 int ret;
1808 struct msghdr msg;
1809 struct iovec iov;
1810 struct cmsghdr *ptr;
1811 char adata[1024];
1812
1813 msg.msg_name = (void *) from;
1814 msg.msg_namelen = sizeof (struct sockaddr_in);
1815 msg.msg_iov = &iov;
1816 msg.msg_iovlen = 1;
1817 msg.msg_control = (void *) adata;
1818 msg.msg_controllen = sizeof adata;
1819 iov.iov_base = buf;
1820 iov.iov_len = size;
1821
1822 ret = recvmsg (sock, &msg, 0);
1823 if (ret < 0)
1824 return ret;
1825
ajsb99760a2005-01-04 16:24:43 +00001826 for (ptr = ZCMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr))
paul718e3742002-12-13 20:15:29 +00001827 if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO)
1828 {
1829 struct in_pktinfo *pktinfo;
1830 int i;
1831
1832 pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr);
1833 i = pktinfo->ipi_ifindex;
1834 }
1835 return ret;
1836}
1837
1838/* RIP packet read function. */
1839int
1840rip_read_new (struct thread *t)
1841{
1842 int ret;
1843 int sock;
1844 char buf[RIP_PACKET_MAXSIZ];
1845 struct sockaddr_in from;
1846 unsigned int ifindex;
1847
1848 /* Fetch socket then register myself. */
1849 sock = THREAD_FD (t);
1850 rip_event (RIP_READ, sock);
1851
1852 /* Read RIP packet. */
1853 ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex);
1854 if (ret < 0)
1855 {
ajs6099b3b2004-11-20 02:06:59 +00001856 zlog_warn ("Can't read RIP packet: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001857 return ret;
1858 }
1859
1860 return ret;
1861}
1862#endif /* RIP_RECVMSG */
1863
1864/* First entry point of RIP packet. */
pauldc63bfd2005-10-25 23:31:05 +00001865static int
paul718e3742002-12-13 20:15:29 +00001866rip_read (struct thread *t)
1867{
1868 int sock;
1869 int ret;
1870 int rtenum;
1871 union rip_buf rip_buf;
1872 struct rip_packet *packet;
1873 struct sockaddr_in from;
paul11dde9c2004-05-31 14:00:00 +00001874 int len;
Paul Jakma3e557ae2006-09-11 02:10:40 +00001875 int vrecv;
paul11dde9c2004-05-31 14:00:00 +00001876 socklen_t fromlen;
paul718e3742002-12-13 20:15:29 +00001877 struct interface *ifp;
paulc49ad8f2004-10-22 10:27:28 +00001878 struct connected *ifc;
paul718e3742002-12-13 20:15:29 +00001879 struct rip_interface *ri;
1880
1881 /* Fetch socket then register myself. */
1882 sock = THREAD_FD (t);
1883 rip->t_read = NULL;
1884
1885 /* Add myself to tne next event */
1886 rip_event (RIP_READ, sock);
1887
1888 /* RIPd manages only IPv4. */
1889 memset (&from, 0, sizeof (struct sockaddr_in));
1890 fromlen = sizeof (struct sockaddr_in);
1891
1892 len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0,
1893 (struct sockaddr *) &from, &fromlen);
1894 if (len < 0)
1895 {
ajs6099b3b2004-11-20 02:06:59 +00001896 zlog_info ("recvfrom failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001897 return len;
1898 }
1899
1900 /* Check is this packet comming from myself? */
paul31a476c2003-09-29 19:54:53 +00001901 if (if_check_address (from.sin_addr))
paul718e3742002-12-13 20:15:29 +00001902 {
1903 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001904 zlog_debug ("ignore packet comes from myself");
paul718e3742002-12-13 20:15:29 +00001905 return -1;
1906 }
1907
1908 /* Which interface is this packet comes from. */
1909 ifp = if_lookup_address (from.sin_addr);
paulc49ad8f2004-10-22 10:27:28 +00001910
paul718e3742002-12-13 20:15:29 +00001911 /* RIP packet received */
1912 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001913 zlog_debug ("RECV packet from %s port %d on %s",
paul718e3742002-12-13 20:15:29 +00001914 inet_ntoa (from.sin_addr), ntohs (from.sin_port),
1915 ifp ? ifp->name : "unknown");
1916
1917 /* If this packet come from unknown interface, ignore it. */
1918 if (ifp == NULL)
1919 {
ajs766a0ca2004-12-15 14:55:51 +00001920 zlog_info ("rip_read: cannot find interface for packet from %s port %d",
1921 inet_ntoa(from.sin_addr), ntohs (from.sin_port));
paulc49ad8f2004-10-22 10:27:28 +00001922 return -1;
1923 }
1924
1925 ifc = connected_lookup_address (ifp, from.sin_addr);
1926
1927 if (ifc == NULL)
1928 {
ajs766a0ca2004-12-15 14:55:51 +00001929 zlog_info ("rip_read: cannot find connected address for packet from %s "
1930 "port %d on interface %s",
1931 inet_ntoa(from.sin_addr), ntohs (from.sin_port), ifp->name);
paul718e3742002-12-13 20:15:29 +00001932 return -1;
1933 }
1934
1935 /* Packet length check. */
1936 if (len < RIP_PACKET_MINSIZ)
1937 {
1938 zlog_warn ("packet size %d is smaller than minimum size %d",
1939 len, RIP_PACKET_MINSIZ);
1940 rip_peer_bad_packet (&from);
1941 return len;
1942 }
1943 if (len > RIP_PACKET_MAXSIZ)
1944 {
1945 zlog_warn ("packet size %d is larger than max size %d",
1946 len, RIP_PACKET_MAXSIZ);
1947 rip_peer_bad_packet (&from);
1948 return len;
1949 }
1950
1951 /* Packet alignment check. */
1952 if ((len - RIP_PACKET_MINSIZ) % 20)
1953 {
1954 zlog_warn ("packet size %d is wrong for RIP packet alignment", len);
1955 rip_peer_bad_packet (&from);
1956 return len;
1957 }
1958
1959 /* Set RTE number. */
1960 rtenum = ((len - RIP_PACKET_MINSIZ) / 20);
1961
1962 /* For easy to handle. */
1963 packet = &rip_buf.rip_packet;
1964
1965 /* RIP version check. */
1966 if (packet->version == 0)
1967 {
1968 zlog_info ("version 0 with command %d received.", packet->command);
1969 rip_peer_bad_packet (&from);
1970 return -1;
1971 }
1972
1973 /* Dump RIP packet. */
1974 if (IS_RIP_DEBUG_RECV)
1975 rip_packet_dump (packet, len, "RECV");
1976
1977 /* RIP version adjust. This code should rethink now. RFC1058 says
1978 that "Version 1 implementations are to ignore this extra data and
1979 process only the fields specified in this document.". So RIPv3
1980 packet should be treated as RIPv1 ignoring must be zero field. */
1981 if (packet->version > RIPv2)
1982 packet->version = RIPv2;
1983
1984 /* Is RIP running or is this RIP neighbor ?*/
1985 ri = ifp->info;
1986 if (! ri->running && ! rip_neighbor_lookup (&from))
1987 {
1988 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001989 zlog_debug ("RIP is not enabled on interface %s.", ifp->name);
paul718e3742002-12-13 20:15:29 +00001990 rip_peer_bad_packet (&from);
1991 return -1;
1992 }
1993
Paul Jakma15a2b082006-05-04 07:36:34 +00001994 /* RIP Version check. RFC2453, 4.6 and 5.1 */
Paul Jakma3e557ae2006-09-11 02:10:40 +00001995 vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ?
1996 rip->version_recv : ri->ri_receive);
Paul Jakma15a2b082006-05-04 07:36:34 +00001997 if ((packet->version == RIPv1) && !(vrecv & RIPv1))
paul718e3742002-12-13 20:15:29 +00001998 {
Paul Jakma15a2b082006-05-04 07:36:34 +00001999 if (IS_RIP_DEBUG_PACKET)
2000 zlog_debug (" packet's v%d doesn't fit to if version spec",
2001 packet->version);
2002 rip_peer_bad_packet (&from);
2003 return -1;
paul718e3742002-12-13 20:15:29 +00002004 }
Paul Jakma15a2b082006-05-04 07:36:34 +00002005 if ((packet->version == RIPv2) && !(vrecv & RIPv2))
2006 {
2007 if (IS_RIP_DEBUG_PACKET)
2008 zlog_debug (" packet's v%d doesn't fit to if version spec",
2009 packet->version);
2010 rip_peer_bad_packet (&from);
2011 return -1;
2012 }
2013
paul718e3742002-12-13 20:15:29 +00002014 /* RFC2453 5.2 If the router is not configured to authenticate RIP-2
2015 messages, then RIP-1 and unauthenticated RIP-2 messages will be
2016 accepted; authenticated RIP-2 messages shall be discarded. */
paul718e3742002-12-13 20:15:29 +00002017 if ((ri->auth_type == RIP_NO_AUTH)
2018 && rtenum
paulca5e5162004-06-06 22:06:33 +00002019 && (packet->version == RIPv2)
2020 && (packet->rte->family == htons(RIP_FAMILY_AUTH)))
paul718e3742002-12-13 20:15:29 +00002021 {
2022 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002023 zlog_debug ("packet RIPv%d is dropped because authentication disabled",
paul718e3742002-12-13 20:15:29 +00002024 packet->version);
2025 rip_peer_bad_packet (&from);
2026 return -1;
2027 }
Paul Jakma15a2b082006-05-04 07:36:34 +00002028
2029 /* RFC:
2030 If the router is configured to authenticate RIP-2 messages, then
paul718e3742002-12-13 20:15:29 +00002031 RIP-1 messages and RIP-2 messages which pass authentication
2032 testing shall be accepted; unauthenticated and failed
2033 authentication RIP-2 messages shall be discarded. For maximum
2034 security, RIP-1 messages should be ignored when authentication is
2035 in use (see section 4.1); otherwise, the routing information from
2036 authenticated messages will be propagated by RIP-1 routers in an
Paul Jakma15a2b082006-05-04 07:36:34 +00002037 unauthenticated manner.
2038 */
2039 /* We make an exception for RIPv1 REQUEST packets, to which we'll
2040 * always reply regardless of authentication settings, because:
2041 *
2042 * - if there other authorised routers on-link, the REQUESTor can
2043 * passively obtain the routing updates anyway
2044 * - if there are no other authorised routers on-link, RIP can
2045 * easily be disabled for the link to prevent giving out information
2046 * on state of this routers RIP routing table..
2047 *
2048 * I.e. if RIPv1 has any place anymore these days, it's as a very
2049 * simple way to distribute routing information (e.g. to embedded
2050 * hosts / appliances) and the ability to give out RIPv1
2051 * routing-information freely, while still requiring RIPv2
2052 * authentication for any RESPONSEs might be vaguely useful.
2053 */
2054 if (ri->auth_type != RIP_NO_AUTH
2055 && packet->version == RIPv1)
paul718e3742002-12-13 20:15:29 +00002056 {
Paul Jakma15a2b082006-05-04 07:36:34 +00002057 /* Discard RIPv1 messages other than REQUESTs */
2058 if (packet->command != RIP_REQUEST)
2059 {
2060 if (IS_RIP_DEBUG_PACKET)
2061 zlog_debug ("RIPv1" " dropped because authentication enabled");
2062 rip_peer_bad_packet (&from);
2063 return -1;
2064 }
2065 }
2066 else if (ri->auth_type != RIP_NO_AUTH)
2067 {
2068 const char *auth_desc;
2069
2070 if (rtenum == 0)
2071 {
2072 /* There definitely is no authentication in the packet. */
2073 if (IS_RIP_DEBUG_PACKET)
2074 zlog_debug ("RIPv2 authentication failed: no auth RTE in packet");
2075 rip_peer_bad_packet (&from);
2076 return -1;
2077 }
2078
2079 /* First RTE must be an Authentication Family RTE */
2080 if (packet->rte->family != htons(RIP_FAMILY_AUTH))
2081 {
2082 if (IS_RIP_DEBUG_PACKET)
2083 zlog_debug ("RIPv2" " dropped because authentication enabled");
paul718e3742002-12-13 20:15:29 +00002084 rip_peer_bad_packet (&from);
2085 return -1;
Paul Jakma15a2b082006-05-04 07:36:34 +00002086 }
2087
paul718e3742002-12-13 20:15:29 +00002088 /* Check RIPv2 authentication. */
Paul Jakma15a2b082006-05-04 07:36:34 +00002089 switch (ntohs(packet->rte->tag))
2090 {
2091 case RIP_AUTH_SIMPLE_PASSWORD:
2092 auth_desc = "simple";
2093 ret = rip_auth_simple_password (packet->rte, &from, ifp);
2094 break;
2095
2096 case RIP_AUTH_MD5:
2097 auth_desc = "MD5";
2098 ret = rip_auth_md5 (packet, &from, len, ifp);
2099 /* Reset RIP packet length to trim MD5 data. */
2100 len = ret;
2101 break;
2102
2103 default:
2104 ret = 0;
2105 auth_desc = "unknown type";
2106 if (IS_RIP_DEBUG_PACKET)
2107 zlog_debug ("RIPv2 Unknown authentication type %d",
2108 ntohs (packet->rte->tag));
2109 }
2110
2111 if (ret)
2112 {
2113 if (IS_RIP_DEBUG_PACKET)
2114 zlog_debug ("RIPv2 %s authentication success", auth_desc);
2115 }
2116 else
2117 {
2118 if (IS_RIP_DEBUG_PACKET)
2119 zlog_debug ("RIPv2 %s authentication failure", auth_desc);
2120 rip_peer_bad_packet (&from);
2121 return -1;
2122 }
paul718e3742002-12-13 20:15:29 +00002123 }
2124
2125 /* Process each command. */
2126 switch (packet->command)
2127 {
2128 case RIP_RESPONSE:
paulc49ad8f2004-10-22 10:27:28 +00002129 rip_response_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002130 break;
2131 case RIP_REQUEST:
2132 case RIP_POLL:
paulc49ad8f2004-10-22 10:27:28 +00002133 rip_request_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002134 break;
2135 case RIP_TRACEON:
2136 case RIP_TRACEOFF:
2137 zlog_info ("Obsolete command %s received, please sent it to routed",
2138 lookup (rip_msg, packet->command));
2139 rip_peer_bad_packet (&from);
2140 break;
2141 case RIP_POLL_ENTRY:
2142 zlog_info ("Obsolete command %s received",
2143 lookup (rip_msg, packet->command));
2144 rip_peer_bad_packet (&from);
2145 break;
2146 default:
2147 zlog_info ("Unknown RIP command %d received", packet->command);
2148 rip_peer_bad_packet (&from);
2149 break;
2150 }
2151
2152 return len;
2153}
2154
paul718e3742002-12-13 20:15:29 +00002155/* Write routing table entry to the stream and return next index of
2156 the routing table entry in the stream. */
pauldc63bfd2005-10-25 23:31:05 +00002157static int
paul718e3742002-12-13 20:15:29 +00002158rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p,
paulb14ee002005-02-04 23:42:41 +00002159 u_char version, struct rip_info *rinfo)
paul718e3742002-12-13 20:15:29 +00002160{
2161 struct in_addr mask;
paul718e3742002-12-13 20:15:29 +00002162
2163 /* Write routing table entry. */
2164 if (version == RIPv1)
2165 {
2166 stream_putw (s, AF_INET);
2167 stream_putw (s, 0);
2168 stream_put_ipv4 (s, p->prefix.s_addr);
2169 stream_put_ipv4 (s, 0);
2170 stream_put_ipv4 (s, 0);
2171 stream_putl (s, rinfo->metric_out);
2172 }
2173 else
2174 {
2175 masklen2ip (p->prefixlen, &mask);
2176
2177 stream_putw (s, AF_INET);
hasso16705132003-05-25 14:49:19 +00002178 stream_putw (s, rinfo->tag_out);
paul718e3742002-12-13 20:15:29 +00002179 stream_put_ipv4 (s, p->prefix.s_addr);
2180 stream_put_ipv4 (s, mask.s_addr);
2181 stream_put_ipv4 (s, rinfo->nexthop_out.s_addr);
2182 stream_putl (s, rinfo->metric_out);
2183 }
2184
2185 return ++num;
2186}
2187
2188/* Send update to the ifp or spcified neighbor. */
2189void
paulc49ad8f2004-10-22 10:27:28 +00002190rip_output_process (struct connected *ifc, struct sockaddr_in *to,
2191 int route_type, u_char version)
paul718e3742002-12-13 20:15:29 +00002192{
2193 int ret;
2194 struct stream *s;
2195 struct route_node *rp;
2196 struct rip_info *rinfo;
2197 struct rip_interface *ri;
2198 struct prefix_ipv4 *p;
2199 struct prefix_ipv4 classfull;
paul727d1042002-12-13 20:50:29 +00002200 struct prefix_ipv4 ifaddrclass;
paulb14ee002005-02-04 23:42:41 +00002201 struct key *key = NULL;
2202 /* this might need to made dynamic if RIP ever supported auth methods
2203 with larger key string sizes */
2204 char auth_str[RIP_AUTH_SIMPLE_SIZE];
pauldc63bfd2005-10-25 23:31:05 +00002205 size_t doff = 0; /* offset of digest offset field */
paul2c61ae32005-08-16 15:22:14 +00002206 int num = 0;
paul718e3742002-12-13 20:15:29 +00002207 int rtemax;
paul01d09082003-06-08 21:22:18 +00002208 int subnetted = 0;
Lu Fengb397cf42014-07-18 06:13:18 +00002209 struct list *list = NULL;
2210 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00002211
2212 /* Logging output event. */
2213 if (IS_RIP_DEBUG_EVENT)
2214 {
2215 if (to)
ajs5d6c3772004-12-08 19:24:06 +00002216 zlog_debug ("update routes to neighbor %s", inet_ntoa (to->sin_addr));
paul718e3742002-12-13 20:15:29 +00002217 else
ajs5d6c3772004-12-08 19:24:06 +00002218 zlog_debug ("update routes on interface %s ifindex %d",
paulc49ad8f2004-10-22 10:27:28 +00002219 ifc->ifp->name, ifc->ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002220 }
2221
2222 /* Set output stream. */
2223 s = rip->obuf;
2224
2225 /* Reset stream and RTE counter. */
2226 stream_reset (s);
Lu Feng342a31b2014-06-25 07:43:15 +00002227 rtemax = RIP_MAX_RTE;
paul718e3742002-12-13 20:15:29 +00002228
2229 /* Get RIP interface. */
paulc49ad8f2004-10-22 10:27:28 +00002230 ri = ifc->ifp->info;
paul718e3742002-12-13 20:15:29 +00002231
2232 /* If output interface is in simple password authentication mode, we
2233 need space for authentication data. */
2234 if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
2235 rtemax -= 1;
2236
2237 /* If output interface is in MD5 authentication mode, we need space
2238 for authentication header and data. */
2239 if (ri->auth_type == RIP_AUTH_MD5)
2240 rtemax -= 2;
2241
2242 /* If output interface is in simple password authentication mode
2243 and string or keychain is specified we need space for auth. data */
paulb14ee002005-02-04 23:42:41 +00002244 if (ri->auth_type != RIP_NO_AUTH)
paul718e3742002-12-13 20:15:29 +00002245 {
2246 if (ri->key_chain)
2247 {
2248 struct keychain *keychain;
2249
2250 keychain = keychain_lookup (ri->key_chain);
2251 if (keychain)
paulb14ee002005-02-04 23:42:41 +00002252 key = key_lookup_for_send (keychain);
paul718e3742002-12-13 20:15:29 +00002253 }
paulb14ee002005-02-04 23:42:41 +00002254 /* to be passed to auth functions later */
2255 rip_auth_prepare_str_send (ri, key, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002256 }
2257
paul727d1042002-12-13 20:50:29 +00002258 if (version == RIPv1)
2259 {
paulc49ad8f2004-10-22 10:27:28 +00002260 memcpy (&ifaddrclass, ifc->address, sizeof (struct prefix_ipv4));
paul727d1042002-12-13 20:50:29 +00002261 apply_classful_mask_ipv4 (&ifaddrclass);
2262 subnetted = 0;
paulc49ad8f2004-10-22 10:27:28 +00002263 if (ifc->address->prefixlen > ifaddrclass.prefixlen)
paul01d09082003-06-08 21:22:18 +00002264 subnetted = 1;
paul727d1042002-12-13 20:50:29 +00002265 }
2266
paul718e3742002-12-13 20:15:29 +00002267 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002268 if ((list = rp->info) != NULL && listcount (list) != 0)
paul718e3742002-12-13 20:15:29 +00002269 {
Lu Fengb397cf42014-07-18 06:13:18 +00002270 rinfo = listgetdata (listhead (list));
paul727d1042002-12-13 20:50:29 +00002271 /* For RIPv1, if we are subnetted, output subnets in our network */
2272 /* that have the same mask as the output "interface". For other */
2273 /* networks, only the classfull version is output. */
paul718e3742002-12-13 20:15:29 +00002274
2275 if (version == RIPv1)
2276 {
paul727d1042002-12-13 20:50:29 +00002277 p = (struct prefix_ipv4 *) &rp->p;
paul718e3742002-12-13 20:15:29 +00002278
2279 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002280 zlog_debug("RIPv1 mask check, %s/%d considered for output",
paul727d1042002-12-13 20:50:29 +00002281 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002282
paul727d1042002-12-13 20:50:29 +00002283 if (subnetted &&
2284 prefix_match ((struct prefix *) &ifaddrclass, &rp->p))
2285 {
paulc49ad8f2004-10-22 10:27:28 +00002286 if ((ifc->address->prefixlen != rp->p.prefixlen) &&
paul727d1042002-12-13 20:50:29 +00002287 (rp->p.prefixlen != 32))
2288 continue;
2289 }
2290 else
2291 {
2292 memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4));
2293 apply_classful_mask_ipv4(&classfull);
2294 if (rp->p.u.prefix4.s_addr != 0 &&
2295 classfull.prefixlen != rp->p.prefixlen)
2296 continue;
2297 }
paul718e3742002-12-13 20:15:29 +00002298 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002299 zlog_debug("RIPv1 mask check, %s/%d made it through",
paul727d1042002-12-13 20:50:29 +00002300 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002301 }
2302 else
2303 p = (struct prefix_ipv4 *) &rp->p;
2304
2305 /* Apply output filters. */
2306 ret = rip_outgoing_filter (p, ri);
2307 if (ret < 0)
2308 continue;
2309
2310 /* Changed route only output. */
2311 if (route_type == rip_changed_route &&
2312 (! (rinfo->flags & RIP_RTF_CHANGED)))
2313 continue;
2314
2315 /* Split horizon. */
2316 /* if (split_horizon == rip_split_horizon) */
hasso16705132003-05-25 14:49:19 +00002317 if (ri->split_horizon == RIP_SPLIT_HORIZON)
paul718e3742002-12-13 20:15:29 +00002318 {
paul42d14d92003-11-17 09:15:18 +00002319 /*
2320 * We perform split horizon for RIP and connected route.
2321 * For rip routes, we want to suppress the route if we would
2322 * end up sending the route back on the interface that we
2323 * learned it from, with a higher metric. For connected routes,
2324 * we suppress the route if the prefix is a subset of the
2325 * source address that we are going to use for the packet
2326 * (in order to handle the case when multiple subnets are
2327 * configured on the same interface).
2328 */
Lu Fengb397cf42014-07-18 06:13:18 +00002329 int suppress = 0;
2330 struct rip_info *tmp_rinfo = NULL;
2331
2332 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
2333 if (tmp_rinfo->type == ZEBRA_ROUTE_RIP &&
2334 tmp_rinfo->ifindex == ifc->ifp->ifindex)
2335 {
2336 suppress = 1;
2337 break;
2338 }
2339
2340 if (!suppress && rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002341 prefix_match((struct prefix *)p, ifc->address))
Lu Fengb397cf42014-07-18 06:13:18 +00002342 suppress = 1;
2343
2344 if (suppress)
paul718e3742002-12-13 20:15:29 +00002345 continue;
2346 }
2347
2348 /* Preparation for route-map. */
2349 rinfo->metric_set = 0;
2350 rinfo->nexthop_out.s_addr = 0;
2351 rinfo->metric_out = rinfo->metric;
hasso16705132003-05-25 14:49:19 +00002352 rinfo->tag_out = rinfo->tag;
paulc49ad8f2004-10-22 10:27:28 +00002353 rinfo->ifindex_out = ifc->ifp->ifindex;
paul718e3742002-12-13 20:15:29 +00002354
hasso16705132003-05-25 14:49:19 +00002355 /* In order to avoid some local loops,
2356 * if the RIP route has a nexthop via this interface, keep the nexthop,
2357 * otherwise set it to 0. The nexthop should not be propagated
2358 * beyond the local broadcast/multicast area in order
2359 * to avoid an IGP multi-level recursive look-up.
2360 * see (4.4)
2361 */
paulc49ad8f2004-10-22 10:27:28 +00002362 if (rinfo->ifindex == ifc->ifp->ifindex)
paul718e3742002-12-13 20:15:29 +00002363 rinfo->nexthop_out = rinfo->nexthop;
hasso16705132003-05-25 14:49:19 +00002364
2365 /* Interface route-map */
2366 if (ri->routemap[RIP_FILTER_OUT])
2367 {
2368 ret = route_map_apply (ri->routemap[RIP_FILTER_OUT],
2369 (struct prefix *) p, RMAP_RIP,
2370 rinfo);
2371
2372 if (ret == RMAP_DENYMATCH)
2373 {
2374 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002375 zlog_debug ("RIP %s/%d is filtered by route-map out",
hasso16705132003-05-25 14:49:19 +00002376 inet_ntoa (p->prefix), p->prefixlen);
2377 continue;
2378 }
2379 }
paul718e3742002-12-13 20:15:29 +00002380
hasso16705132003-05-25 14:49:19 +00002381 /* Apply redistribute route map - continue, if deny */
paul718e3742002-12-13 20:15:29 +00002382 if (rip->route_map[rinfo->type].name
2383 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2384 {
2385 ret = route_map_apply (rip->route_map[rinfo->type].map,
2386 (struct prefix *)p, RMAP_RIP, rinfo);
2387
2388 if (ret == RMAP_DENYMATCH)
2389 {
2390 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002391 zlog_debug ("%s/%d is filtered by route-map",
paul718e3742002-12-13 20:15:29 +00002392 inet_ntoa (p->prefix), p->prefixlen);
2393 continue;
2394 }
2395 }
2396
2397 /* When route-map does not set metric. */
2398 if (! rinfo->metric_set)
2399 {
2400 /* If redistribute metric is set. */
2401 if (rip->route_map[rinfo->type].metric_config
2402 && rinfo->metric != RIP_METRIC_INFINITY)
2403 {
2404 rinfo->metric_out = rip->route_map[rinfo->type].metric;
2405 }
2406 else
2407 {
2408 /* If the route is not connected or localy generated
2409 one, use default-metric value*/
2410 if (rinfo->type != ZEBRA_ROUTE_RIP
2411 && rinfo->type != ZEBRA_ROUTE_CONNECT
2412 && rinfo->metric != RIP_METRIC_INFINITY)
2413 rinfo->metric_out = rip->default_metric;
2414 }
2415 }
2416
2417 /* Apply offset-list */
2418 if (rinfo->metric != RIP_METRIC_INFINITY)
paulc49ad8f2004-10-22 10:27:28 +00002419 rip_offset_list_apply_out (p, ifc->ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00002420
2421 if (rinfo->metric_out > RIP_METRIC_INFINITY)
2422 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002423
2424 /* Perform split-horizon with poisoned reverse
2425 * for RIP and connected routes.
2426 **/
2427 if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) {
paul42d14d92003-11-17 09:15:18 +00002428 /*
2429 * We perform split horizon for RIP and connected route.
2430 * For rip routes, we want to suppress the route if we would
2431 * end up sending the route back on the interface that we
2432 * learned it from, with a higher metric. For connected routes,
2433 * we suppress the route if the prefix is a subset of the
2434 * source address that we are going to use for the packet
2435 * (in order to handle the case when multiple subnets are
2436 * configured on the same interface).
2437 */
Lu Fengb397cf42014-07-18 06:13:18 +00002438 struct rip_info *tmp_rinfo = NULL;
2439
2440 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
2441 if (tmp_rinfo->type == ZEBRA_ROUTE_RIP &&
2442 tmp_rinfo->ifindex == ifc->ifp->ifindex)
2443 rinfo->metric_out = RIP_METRIC_INFINITY;
2444 if (tmp_rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002445 prefix_match((struct prefix *)p, ifc->address))
Lu Fengb397cf42014-07-18 06:13:18 +00002446 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002447 }
paulb14ee002005-02-04 23:42:41 +00002448
2449 /* Prepare preamble, auth headers, if needs be */
2450 if (num == 0)
2451 {
2452 stream_putc (s, RIP_RESPONSE);
2453 stream_putc (s, version);
2454 stream_putw (s, 0);
2455
paul0cb8a012005-05-29 11:27:24 +00002456 /* auth header for !v1 && !no_auth */
2457 if ( (ri->auth_type != RIP_NO_AUTH) && (version != RIPv1) )
paulb14ee002005-02-04 23:42:41 +00002458 doff = rip_auth_header_write (s, ri, key, auth_str,
2459 RIP_AUTH_SIMPLE_SIZE);
2460 }
2461
paul718e3742002-12-13 20:15:29 +00002462 /* Write RTE to the stream. */
paulb14ee002005-02-04 23:42:41 +00002463 num = rip_write_rte (num, s, p, version, rinfo);
paul718e3742002-12-13 20:15:29 +00002464 if (num == rtemax)
2465 {
2466 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002467 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002468
2469 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s),
paulc49ad8f2004-10-22 10:27:28 +00002470 to, ifc);
paul718e3742002-12-13 20:15:29 +00002471
2472 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2473 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2474 stream_get_endp(s), "SEND");
2475 num = 0;
2476 stream_reset (s);
2477 }
2478 }
2479
2480 /* Flush unwritten RTE. */
2481 if (num != 0)
2482 {
2483 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002484 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002485
paulc49ad8f2004-10-22 10:27:28 +00002486 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifc);
paul718e3742002-12-13 20:15:29 +00002487
2488 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2489 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2490 stream_get_endp (s), "SEND");
2491 num = 0;
2492 stream_reset (s);
2493 }
2494
2495 /* Statistics updates. */
2496 ri->sent_updates++;
2497}
2498
2499/* Send RIP packet to the interface. */
pauldc63bfd2005-10-25 23:31:05 +00002500static void
paulc49ad8f2004-10-22 10:27:28 +00002501rip_update_interface (struct connected *ifc, u_char version, int route_type)
paul718e3742002-12-13 20:15:29 +00002502{
paul718e3742002-12-13 20:15:29 +00002503 struct sockaddr_in to;
2504
2505 /* When RIP version is 2 and multicast enable interface. */
paulc49ad8f2004-10-22 10:27:28 +00002506 if (version == RIPv2 && if_is_multicast (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002507 {
2508 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002509 zlog_debug ("multicast announce on %s ", ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002510
paulc49ad8f2004-10-22 10:27:28 +00002511 rip_output_process (ifc, NULL, route_type, version);
paul718e3742002-12-13 20:15:29 +00002512 return;
2513 }
paulc49ad8f2004-10-22 10:27:28 +00002514
paul718e3742002-12-13 20:15:29 +00002515 /* If we can't send multicast packet, send it with unicast. */
paulc49ad8f2004-10-22 10:27:28 +00002516 if (if_is_broadcast (ifc->ifp) || if_is_pointopoint (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002517 {
paulc49ad8f2004-10-22 10:27:28 +00002518 if (ifc->address->family == AF_INET)
2519 {
2520 /* Destination address and port setting. */
2521 memset (&to, 0, sizeof (struct sockaddr_in));
2522 if (ifc->destination)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002523 /* use specified broadcast or peer destination addr */
paulc49ad8f2004-10-22 10:27:28 +00002524 to.sin_addr = ifc->destination->u.prefix4;
Andrew J. Schorre4529632006-12-12 19:18:21 +00002525 else if (ifc->address->prefixlen < IPV4_MAX_PREFIXLEN)
paulc49ad8f2004-10-22 10:27:28 +00002526 /* calculate the appropriate broadcast address */
2527 to.sin_addr.s_addr =
2528 ipv4_broadcast_addr(ifc->address->u.prefix4.s_addr,
2529 ifc->address->prefixlen);
Andrew J. Schorre4529632006-12-12 19:18:21 +00002530 else
2531 /* do not know where to send the packet */
2532 return;
paulc49ad8f2004-10-22 10:27:28 +00002533 to.sin_port = htons (RIP_PORT_DEFAULT);
paul718e3742002-12-13 20:15:29 +00002534
paulc49ad8f2004-10-22 10:27:28 +00002535 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002536 zlog_debug("%s announce to %s on %s",
2537 CONNECTED_PEER(ifc) ? "unicast" : "broadcast",
2538 inet_ntoa (to.sin_addr), ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002539
paulc49ad8f2004-10-22 10:27:28 +00002540 rip_output_process (ifc, &to, route_type, version);
2541 }
paul718e3742002-12-13 20:15:29 +00002542 }
2543}
2544
2545/* Update send to all interface and neighbor. */
pauldc63bfd2005-10-25 23:31:05 +00002546static void
paul718e3742002-12-13 20:15:29 +00002547rip_update_process (int route_type)
2548{
paul1eb8ef22005-04-07 07:30:20 +00002549 struct listnode *node;
2550 struct listnode *ifnode, *ifnnode;
paulcc1131a2003-10-15 23:20:17 +00002551 struct connected *connected;
paul718e3742002-12-13 20:15:29 +00002552 struct interface *ifp;
2553 struct rip_interface *ri;
2554 struct route_node *rp;
2555 struct sockaddr_in to;
2556 struct prefix_ipv4 *p;
2557
2558 /* Send RIP update to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00002559 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00002560 {
paul718e3742002-12-13 20:15:29 +00002561 if (if_is_loopback (ifp))
2562 continue;
2563
paul2e3b2e42002-12-13 21:03:13 +00002564 if (! if_is_operative (ifp))
paul718e3742002-12-13 20:15:29 +00002565 continue;
2566
2567 /* Fetch RIP interface information. */
2568 ri = ifp->info;
2569
2570 /* When passive interface is specified, suppress announce to the
2571 interface. */
2572 if (ri->passive)
2573 continue;
2574
2575 if (ri->running)
2576 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002577 /*
2578 * If there is no version configuration in the interface,
2579 * use rip's version setting.
2580 */
2581 int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
2582 rip->version_send : ri->ri_send);
2583
paul718e3742002-12-13 20:15:29 +00002584 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002585 zlog_debug("SEND UPDATE to %s ifindex %d",
2586 (ifp->name ? ifp->name : "_unknown_"), ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002587
paulcc1131a2003-10-15 23:20:17 +00002588 /* send update on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002589 for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002590 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002591 if (connected->address->family == AF_INET)
2592 {
2593 if (vsend & RIPv1)
2594 rip_update_interface (connected, RIPv1, route_type);
2595 if ((vsend & RIPv2) && if_is_multicast(ifp))
2596 rip_update_interface (connected, RIPv2, route_type);
2597 }
2598 }
paul718e3742002-12-13 20:15:29 +00002599 }
2600 }
2601
2602 /* RIP send updates to each neighbor. */
2603 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
2604 if (rp->info != NULL)
2605 {
2606 p = (struct prefix_ipv4 *) &rp->p;
2607
2608 ifp = if_lookup_address (p->prefix);
2609 if (! ifp)
2610 {
paulc49ad8f2004-10-22 10:27:28 +00002611 zlog_warn ("Neighbor %s doesnt have connected interface!",
paul718e3742002-12-13 20:15:29 +00002612 inet_ntoa (p->prefix));
2613 continue;
2614 }
paulc49ad8f2004-10-22 10:27:28 +00002615
2616 if ( (connected = connected_lookup_address (ifp, p->prefix)) == NULL)
2617 {
2618 zlog_warn ("Neighbor %s doesnt have connected network",
2619 inet_ntoa (p->prefix));
2620 continue;
2621 }
2622
paul718e3742002-12-13 20:15:29 +00002623 /* Set destination address and port */
2624 memset (&to, 0, sizeof (struct sockaddr_in));
2625 to.sin_addr = p->prefix;
2626 to.sin_port = htons (RIP_PORT_DEFAULT);
2627
2628 /* RIP version is rip's configuration. */
paulc49ad8f2004-10-22 10:27:28 +00002629 rip_output_process (connected, &to, route_type, rip->version_send);
paul718e3742002-12-13 20:15:29 +00002630 }
2631}
2632
2633/* RIP's periodical timer. */
pauldc63bfd2005-10-25 23:31:05 +00002634static int
paul718e3742002-12-13 20:15:29 +00002635rip_update (struct thread *t)
2636{
2637 /* Clear timer pointer. */
2638 rip->t_update = NULL;
2639
2640 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002641 zlog_debug ("update timer fire!");
paul718e3742002-12-13 20:15:29 +00002642
2643 /* Process update output. */
2644 rip_update_process (rip_all_route);
2645
2646 /* Triggered updates may be suppressed if a regular update is due by
2647 the time the triggered update would be sent. */
2648 if (rip->t_triggered_interval)
2649 {
2650 thread_cancel (rip->t_triggered_interval);
2651 rip->t_triggered_interval = NULL;
2652 }
2653 rip->trigger = 0;
2654
2655 /* Register myself. */
2656 rip_event (RIP_UPDATE_EVENT, 0);
2657
2658 return 0;
2659}
2660
2661/* Walk down the RIP routing table then clear changed flag. */
pauldc63bfd2005-10-25 23:31:05 +00002662static void
paul216565a2005-10-25 23:35:28 +00002663rip_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00002664{
2665 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00002666 struct rip_info *rinfo = NULL;
2667 struct list *list = NULL;
2668 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00002669
2670 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002671 if ((list = rp->info) != NULL)
2672 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
2673 {
2674 UNSET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
2675 /* This flag can be set only on the first entry. */
2676 break;
2677 }
paul718e3742002-12-13 20:15:29 +00002678}
2679
2680/* Triggered update interval timer. */
pauldc63bfd2005-10-25 23:31:05 +00002681static int
paul718e3742002-12-13 20:15:29 +00002682rip_triggered_interval (struct thread *t)
2683{
2684 int rip_triggered_update (struct thread *);
2685
2686 rip->t_triggered_interval = NULL;
2687
2688 if (rip->trigger)
2689 {
2690 rip->trigger = 0;
2691 rip_triggered_update (t);
2692 }
2693 return 0;
2694}
2695
2696/* Execute triggered update. */
pauldc63bfd2005-10-25 23:31:05 +00002697static int
paul718e3742002-12-13 20:15:29 +00002698rip_triggered_update (struct thread *t)
2699{
2700 int interval;
2701
2702 /* Clear thred pointer. */
2703 rip->t_triggered_update = NULL;
2704
2705 /* Cancel interval timer. */
2706 if (rip->t_triggered_interval)
2707 {
2708 thread_cancel (rip->t_triggered_interval);
2709 rip->t_triggered_interval = NULL;
2710 }
2711 rip->trigger = 0;
2712
2713 /* Logging triggered update. */
2714 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002715 zlog_debug ("triggered update!");
paul718e3742002-12-13 20:15:29 +00002716
2717 /* Split Horizon processing is done when generating triggered
2718 updates as well as normal updates (see section 2.6). */
2719 rip_update_process (rip_changed_route);
2720
2721 /* Once all of the triggered updates have been generated, the route
2722 change flags should be cleared. */
2723 rip_clear_changed_flag ();
2724
2725 /* After a triggered update is sent, a timer should be set for a
2726 random interval between 1 and 5 seconds. If other changes that
2727 would trigger updates occur before the timer expires, a single
2728 update is triggered when the timer expires. */
2729 interval = (random () % 5) + 1;
2730
2731 rip->t_triggered_interval =
2732 thread_add_timer (master, rip_triggered_interval, NULL, interval);
2733
2734 return 0;
2735}
2736
2737/* Withdraw redistributed route. */
2738void
2739rip_redistribute_withdraw (int type)
2740{
2741 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00002742 struct rip_info *rinfo = NULL;
2743 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +00002744
2745 if (!rip)
2746 return;
2747
2748 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002749 if ((list = rp->info) != NULL)
paul718e3742002-12-13 20:15:29 +00002750 {
Lu Fengb397cf42014-07-18 06:13:18 +00002751 rinfo = listgetdata (listhead (list));
paul718e3742002-12-13 20:15:29 +00002752 if (rinfo->type == type
2753 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2754 {
2755 /* Perform poisoned reverse. */
2756 rinfo->metric = RIP_METRIC_INFINITY;
2757 RIP_TIMER_ON (rinfo->t_garbage_collect,
2758 rip_garbage_collect, rip->garbage_time);
2759 RIP_TIMER_OFF (rinfo->t_timeout);
2760 rinfo->flags |= RIP_RTF_CHANGED;
2761
hasso16705132003-05-25 14:49:19 +00002762 if (IS_RIP_DEBUG_EVENT) {
2763 struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p;
2764
ajs5d6c3772004-12-08 19:24:06 +00002765 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]",
hasso16705132003-05-25 14:49:19 +00002766 inet_ntoa(p->prefix), p->prefixlen,
2767 ifindex2ifname(rinfo->ifindex));
2768 }
2769
paul718e3742002-12-13 20:15:29 +00002770 rip_event (RIP_TRIGGERED_UPDATE, 0);
2771 }
2772 }
2773}
2774
2775/* Create new RIP instance and set it to global variable. */
pauldc63bfd2005-10-25 23:31:05 +00002776static int
2777rip_create (void)
paul718e3742002-12-13 20:15:29 +00002778{
Stephen Hemminger393deb92008-08-18 14:13:29 -07002779 rip = XCALLOC (MTYPE_RIP, sizeof (struct rip));
paul718e3742002-12-13 20:15:29 +00002780
2781 /* Set initial value. */
paulf38a4712003-06-07 01:10:00 +00002782 rip->version_send = RI_RIP_VERSION_2;
2783 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002784 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
2785 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
2786 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
2787 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
2788
2789 /* Initialize RIP routig table. */
2790 rip->table = route_table_init ();
2791 rip->route = route_table_init ();
2792 rip->neighbor = route_table_init ();
2793
2794 /* Make output stream. */
2795 rip->obuf = stream_new (1500);
2796
2797 /* Make socket. */
paulf69bd9d2005-06-03 18:01:50 +00002798 rip->sock = rip_create_socket (NULL);
paul718e3742002-12-13 20:15:29 +00002799 if (rip->sock < 0)
2800 return rip->sock;
2801
2802 /* Create read and timer thread. */
2803 rip_event (RIP_READ, rip->sock);
2804 rip_event (RIP_UPDATE_EVENT, 1);
2805
2806 return 0;
2807}
2808
2809/* Sned RIP request to the destination. */
2810int
2811rip_request_send (struct sockaddr_in *to, struct interface *ifp,
paul931cd542004-01-23 15:31:42 +00002812 u_char version, struct connected *connected)
paul718e3742002-12-13 20:15:29 +00002813{
2814 struct rte *rte;
2815 struct rip_packet rip_packet;
paul1eb8ef22005-04-07 07:30:20 +00002816 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00002817
2818 memset (&rip_packet, 0, sizeof (rip_packet));
2819
2820 rip_packet.command = RIP_REQUEST;
2821 rip_packet.version = version;
2822 rte = rip_packet.rte;
2823 rte->metric = htonl (RIP_METRIC_INFINITY);
2824
paul931cd542004-01-23 15:31:42 +00002825 if (connected)
2826 {
2827 /*
2828 * connected is only sent for ripv1 case, or when
2829 * interface does not support multicast. Caller loops
2830 * over each connected address for this case.
2831 */
paul11dde9c2004-05-31 14:00:00 +00002832 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002833 to, connected) != sizeof (rip_packet))
paul931cd542004-01-23 15:31:42 +00002834 return -1;
2835 else
2836 return sizeof (rip_packet);
2837 }
2838
paulcc1131a2003-10-15 23:20:17 +00002839 /* send request on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002840 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002841 {
2842 struct prefix_ipv4 *p;
2843
2844 p = (struct prefix_ipv4 *) connected->address;
2845
2846 if (p->family != AF_INET)
2847 continue;
2848
paul11dde9c2004-05-31 14:00:00 +00002849 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002850 to, connected) != sizeof (rip_packet))
paulcc1131a2003-10-15 23:20:17 +00002851 return -1;
2852 }
2853 return sizeof (rip_packet);
paul718e3742002-12-13 20:15:29 +00002854}
David Lamparter6b0655a2014-06-04 06:53:35 +02002855
pauldc63bfd2005-10-25 23:31:05 +00002856static int
paul718e3742002-12-13 20:15:29 +00002857rip_update_jitter (unsigned long time)
2858{
paul239389b2004-05-05 14:09:37 +00002859#define JITTER_BOUND 4
2860 /* We want to get the jitter to +/- 1/JITTER_BOUND the interval.
2861 Given that, we cannot let time be less than JITTER_BOUND seconds.
2862 The RIPv2 RFC says jitter should be small compared to
2863 update_time. We consider 1/JITTER_BOUND to be small.
2864 */
2865
2866 int jitter_input = time;
2867 int jitter;
2868
2869 if (jitter_input < JITTER_BOUND)
2870 jitter_input = JITTER_BOUND;
2871
2872 jitter = (((rand () % ((jitter_input * 2) + 1)) - jitter_input));
2873
2874 return jitter/JITTER_BOUND;
paul718e3742002-12-13 20:15:29 +00002875}
2876
2877void
2878rip_event (enum rip_event event, int sock)
2879{
2880 int jitter = 0;
2881
2882 switch (event)
2883 {
2884 case RIP_READ:
2885 rip->t_read = thread_add_read (master, rip_read, NULL, sock);
2886 break;
2887 case RIP_UPDATE_EVENT:
2888 if (rip->t_update)
2889 {
2890 thread_cancel (rip->t_update);
2891 rip->t_update = NULL;
2892 }
2893 jitter = rip_update_jitter (rip->update_time);
2894 rip->t_update =
2895 thread_add_timer (master, rip_update, NULL,
2896 sock ? 2 : rip->update_time + jitter);
2897 break;
2898 case RIP_TRIGGERED_UPDATE:
2899 if (rip->t_triggered_interval)
2900 rip->trigger = 1;
2901 else if (! rip->t_triggered_update)
2902 rip->t_triggered_update =
2903 thread_add_event (master, rip_triggered_update, NULL, 0);
2904 break;
2905 default:
2906 break;
2907 }
2908}
David Lamparter6b0655a2014-06-04 06:53:35 +02002909
paul718e3742002-12-13 20:15:29 +00002910DEFUN (router_rip,
2911 router_rip_cmd,
2912 "router rip",
2913 "Enable a routing process\n"
2914 "Routing Information Protocol (RIP)\n")
2915{
2916 int ret;
2917
2918 /* If rip is not enabled before. */
2919 if (! rip)
2920 {
2921 ret = rip_create ();
2922 if (ret < 0)
2923 {
2924 zlog_info ("Can't create RIP");
2925 return CMD_WARNING;
2926 }
2927 }
2928 vty->node = RIP_NODE;
2929 vty->index = rip;
2930
2931 return CMD_SUCCESS;
2932}
2933
2934DEFUN (no_router_rip,
2935 no_router_rip_cmd,
2936 "no router rip",
2937 NO_STR
2938 "Enable a routing process\n"
2939 "Routing Information Protocol (RIP)\n")
2940{
2941 if (rip)
2942 rip_clean ();
2943 return CMD_SUCCESS;
2944}
2945
2946DEFUN (rip_version,
2947 rip_version_cmd,
2948 "version <1-2>",
2949 "Set routing protocol version\n"
2950 "version\n")
2951{
2952 int version;
2953
2954 version = atoi (argv[0]);
2955 if (version != RIPv1 && version != RIPv2)
2956 {
2957 vty_out (vty, "invalid rip version %d%s", version,
2958 VTY_NEWLINE);
2959 return CMD_WARNING;
2960 }
paulf38a4712003-06-07 01:10:00 +00002961 rip->version_send = version;
2962 rip->version_recv = version;
paul718e3742002-12-13 20:15:29 +00002963
2964 return CMD_SUCCESS;
2965}
2966
2967DEFUN (no_rip_version,
2968 no_rip_version_cmd,
2969 "no version",
2970 NO_STR
2971 "Set routing protocol version\n")
2972{
2973 /* Set RIP version to the default. */
paulf38a4712003-06-07 01:10:00 +00002974 rip->version_send = RI_RIP_VERSION_2;
2975 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002976
2977 return CMD_SUCCESS;
2978}
2979
2980ALIAS (no_rip_version,
2981 no_rip_version_val_cmd,
2982 "no version <1-2>",
2983 NO_STR
2984 "Set routing protocol version\n"
2985 "version\n")
2986
2987DEFUN (rip_route,
2988 rip_route_cmd,
2989 "route A.B.C.D/M",
2990 "RIP static route configuration\n"
2991 "IP prefix <network>/<length>\n")
2992{
2993 int ret;
2994 struct prefix_ipv4 p;
2995 struct route_node *node;
2996
2997 ret = str2prefix_ipv4 (argv[0], &p);
2998 if (ret < 0)
2999 {
3000 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
3001 return CMD_WARNING;
3002 }
3003 apply_mask_ipv4 (&p);
3004
3005 /* For router rip configuration. */
3006 node = route_node_get (rip->route, (struct prefix *) &p);
3007
3008 if (node->info)
3009 {
3010 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
3011 route_unlock_node (node);
3012 return CMD_WARNING;
3013 }
3014
hasso8a676be2004-10-08 06:36:38 +00003015 node->info = (char *)"static";
paul718e3742002-12-13 20:15:29 +00003016
vincentfbf5d032005-09-29 11:25:50 +00003017 rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0);
paul718e3742002-12-13 20:15:29 +00003018
3019 return CMD_SUCCESS;
3020}
3021
3022DEFUN (no_rip_route,
3023 no_rip_route_cmd,
3024 "no route A.B.C.D/M",
3025 NO_STR
3026 "RIP static route configuration\n"
3027 "IP prefix <network>/<length>\n")
3028{
3029 int ret;
3030 struct prefix_ipv4 p;
3031 struct route_node *node;
3032
3033 ret = str2prefix_ipv4 (argv[0], &p);
3034 if (ret < 0)
3035 {
3036 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
3037 return CMD_WARNING;
3038 }
3039 apply_mask_ipv4 (&p);
3040
3041 /* For router rip configuration. */
3042 node = route_node_lookup (rip->route, (struct prefix *) &p);
3043 if (! node)
3044 {
3045 vty_out (vty, "Can't find route %s.%s", argv[0],
3046 VTY_NEWLINE);
3047 return CMD_WARNING;
3048 }
3049
3050 rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
3051 route_unlock_node (node);
3052
3053 node->info = NULL;
3054 route_unlock_node (node);
3055
3056 return CMD_SUCCESS;
3057}
3058
Stephen Hemminger2c239702009-12-10 19:16:05 +03003059#if 0
pauldc63bfd2005-10-25 23:31:05 +00003060static void
paul216565a2005-10-25 23:35:28 +00003061rip_update_default_metric (void)
paul718e3742002-12-13 20:15:29 +00003062{
3063 struct route_node *np;
Lu Fengb397cf42014-07-18 06:13:18 +00003064 struct rip_info *rinfo = NULL;
3065 struct list *list = NULL;
3066 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00003067
3068 for (np = route_top (rip->table); np; np = route_next (np))
Lu Fengb397cf42014-07-18 06:13:18 +00003069 if ((list = np->info) != NULL)
3070 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
3071 if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)
3072 rinfo->metric = rip->default_metric;
paul718e3742002-12-13 20:15:29 +00003073}
Stephen Hemminger2c239702009-12-10 19:16:05 +03003074#endif
paul718e3742002-12-13 20:15:29 +00003075
3076DEFUN (rip_default_metric,
3077 rip_default_metric_cmd,
3078 "default-metric <1-16>",
3079 "Set a metric of redistribute routes\n"
3080 "Default metric\n")
3081{
3082 if (rip)
3083 {
3084 rip->default_metric = atoi (argv[0]);
3085 /* rip_update_default_metric (); */
3086 }
3087 return CMD_SUCCESS;
3088}
3089
3090DEFUN (no_rip_default_metric,
3091 no_rip_default_metric_cmd,
3092 "no default-metric",
3093 NO_STR
3094 "Set a metric of redistribute routes\n"
3095 "Default metric\n")
3096{
3097 if (rip)
3098 {
3099 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
3100 /* rip_update_default_metric (); */
3101 }
3102 return CMD_SUCCESS;
3103}
3104
3105ALIAS (no_rip_default_metric,
3106 no_rip_default_metric_val_cmd,
3107 "no default-metric <1-16>",
3108 NO_STR
3109 "Set a metric of redistribute routes\n"
3110 "Default metric\n")
3111
3112DEFUN (rip_timers,
3113 rip_timers_cmd,
3114 "timers basic <5-2147483647> <5-2147483647> <5-2147483647>",
3115 "Adjust routing timers\n"
3116 "Basic routing protocol update timers\n"
3117 "Routing table update timer value in second. Default is 30.\n"
3118 "Routing information timeout timer. Default is 180.\n"
3119 "Garbage collection timer. Default is 120.\n")
3120{
3121 unsigned long update;
3122 unsigned long timeout;
3123 unsigned long garbage;
3124 char *endptr = NULL;
3125 unsigned long RIP_TIMER_MAX = 2147483647;
3126 unsigned long RIP_TIMER_MIN = 5;
3127
3128 update = strtoul (argv[0], &endptr, 10);
3129 if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')
3130 {
3131 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
3132 return CMD_WARNING;
3133 }
3134
3135 timeout = strtoul (argv[1], &endptr, 10);
3136 if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0')
3137 {
3138 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
3139 return CMD_WARNING;
3140 }
3141
3142 garbage = strtoul (argv[2], &endptr, 10);
3143 if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0')
3144 {
3145 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
3146 return CMD_WARNING;
3147 }
3148
3149 /* Set each timer value. */
3150 rip->update_time = update;
3151 rip->timeout_time = timeout;
3152 rip->garbage_time = garbage;
3153
3154 /* Reset update timer thread. */
3155 rip_event (RIP_UPDATE_EVENT, 0);
3156
3157 return CMD_SUCCESS;
3158}
3159
3160DEFUN (no_rip_timers,
3161 no_rip_timers_cmd,
3162 "no timers basic",
3163 NO_STR
3164 "Adjust routing timers\n"
3165 "Basic routing protocol update timers\n")
3166{
3167 /* Set each timer value to the default. */
3168 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
3169 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
3170 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
3171
3172 /* Reset update timer thread. */
3173 rip_event (RIP_UPDATE_EVENT, 0);
3174
3175 return CMD_SUCCESS;
3176}
hasso16705132003-05-25 14:49:19 +00003177
3178ALIAS (no_rip_timers,
3179 no_rip_timers_val_cmd,
3180 "no timers basic <0-65535> <0-65535> <0-65535>",
3181 NO_STR
3182 "Adjust routing timers\n"
3183 "Basic routing protocol update timers\n"
3184 "Routing table update timer value in second. Default is 30.\n"
3185 "Routing information timeout timer. Default is 180.\n"
3186 "Garbage collection timer. Default is 120.\n")
3187
David Lamparter6b0655a2014-06-04 06:53:35 +02003188
paul718e3742002-12-13 20:15:29 +00003189struct route_table *rip_distance_table;
3190
3191struct rip_distance
3192{
3193 /* Distance value for the IP source prefix. */
3194 u_char distance;
3195
3196 /* Name of the access-list to be matched. */
3197 char *access_list;
3198};
3199
pauldc63bfd2005-10-25 23:31:05 +00003200static struct rip_distance *
paul216565a2005-10-25 23:35:28 +00003201rip_distance_new (void)
paul718e3742002-12-13 20:15:29 +00003202{
Stephen Hemminger393deb92008-08-18 14:13:29 -07003203 return XCALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance));
paul718e3742002-12-13 20:15:29 +00003204}
3205
pauldc63bfd2005-10-25 23:31:05 +00003206static void
paul718e3742002-12-13 20:15:29 +00003207rip_distance_free (struct rip_distance *rdistance)
3208{
3209 XFREE (MTYPE_RIP_DISTANCE, rdistance);
3210}
3211
pauldc63bfd2005-10-25 23:31:05 +00003212static int
hasso98b718a2004-10-11 12:57:57 +00003213rip_distance_set (struct vty *vty, const char *distance_str, const char *ip_str,
3214 const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003215{
3216 int ret;
3217 struct prefix_ipv4 p;
3218 u_char distance;
3219 struct route_node *rn;
3220 struct rip_distance *rdistance;
3221
3222 ret = str2prefix_ipv4 (ip_str, &p);
3223 if (ret == 0)
3224 {
3225 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3226 return CMD_WARNING;
3227 }
3228
3229 distance = atoi (distance_str);
3230
3231 /* Get RIP distance node. */
3232 rn = route_node_get (rip_distance_table, (struct prefix *) &p);
3233 if (rn->info)
3234 {
3235 rdistance = rn->info;
3236 route_unlock_node (rn);
3237 }
3238 else
3239 {
3240 rdistance = rip_distance_new ();
3241 rn->info = rdistance;
3242 }
3243
3244 /* Set distance value. */
3245 rdistance->distance = distance;
3246
3247 /* Reset access-list configuration. */
3248 if (rdistance->access_list)
3249 {
3250 free (rdistance->access_list);
3251 rdistance->access_list = NULL;
3252 }
3253 if (access_list_str)
3254 rdistance->access_list = strdup (access_list_str);
3255
3256 return CMD_SUCCESS;
3257}
3258
pauldc63bfd2005-10-25 23:31:05 +00003259static int
hasso98b718a2004-10-11 12:57:57 +00003260rip_distance_unset (struct vty *vty, const char *distance_str,
3261 const char *ip_str, const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003262{
3263 int ret;
3264 struct prefix_ipv4 p;
3265 u_char distance;
3266 struct route_node *rn;
3267 struct rip_distance *rdistance;
3268
3269 ret = str2prefix_ipv4 (ip_str, &p);
3270 if (ret == 0)
3271 {
3272 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3273 return CMD_WARNING;
3274 }
3275
3276 distance = atoi (distance_str);
3277
3278 rn = route_node_lookup (rip_distance_table, (struct prefix *)&p);
3279 if (! rn)
3280 {
3281 vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE);
3282 return CMD_WARNING;
3283 }
3284
3285 rdistance = rn->info;
3286
3287 if (rdistance->access_list)
3288 free (rdistance->access_list);
3289 rip_distance_free (rdistance);
3290
3291 rn->info = NULL;
3292 route_unlock_node (rn);
3293 route_unlock_node (rn);
3294
3295 return CMD_SUCCESS;
3296}
3297
pauldc63bfd2005-10-25 23:31:05 +00003298static void
paul216565a2005-10-25 23:35:28 +00003299rip_distance_reset (void)
paul718e3742002-12-13 20:15:29 +00003300{
3301 struct route_node *rn;
3302 struct rip_distance *rdistance;
3303
3304 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3305 if ((rdistance = rn->info) != NULL)
3306 {
3307 if (rdistance->access_list)
3308 free (rdistance->access_list);
3309 rip_distance_free (rdistance);
3310 rn->info = NULL;
3311 route_unlock_node (rn);
3312 }
3313}
3314
3315/* Apply RIP information to distance method. */
3316u_char
3317rip_distance_apply (struct rip_info *rinfo)
3318{
3319 struct route_node *rn;
3320 struct prefix_ipv4 p;
3321 struct rip_distance *rdistance;
3322 struct access_list *alist;
3323
3324 if (! rip)
3325 return 0;
3326
3327 memset (&p, 0, sizeof (struct prefix_ipv4));
3328 p.family = AF_INET;
3329 p.prefix = rinfo->from;
3330 p.prefixlen = IPV4_MAX_BITLEN;
3331
3332 /* Check source address. */
3333 rn = route_node_match (rip_distance_table, (struct prefix *) &p);
3334 if (rn)
3335 {
3336 rdistance = rn->info;
3337 route_unlock_node (rn);
3338
3339 if (rdistance->access_list)
3340 {
3341 alist = access_list_lookup (AFI_IP, rdistance->access_list);
3342 if (alist == NULL)
3343 return 0;
3344 if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY)
3345 return 0;
3346
3347 return rdistance->distance;
3348 }
3349 else
3350 return rdistance->distance;
3351 }
3352
3353 if (rip->distance)
3354 return rip->distance;
3355
3356 return 0;
3357}
3358
pauldc63bfd2005-10-25 23:31:05 +00003359static void
paul718e3742002-12-13 20:15:29 +00003360rip_distance_show (struct vty *vty)
3361{
3362 struct route_node *rn;
3363 struct rip_distance *rdistance;
3364 int header = 1;
3365 char buf[BUFSIZ];
3366
3367 vty_out (vty, " Distance: (default is %d)%s",
3368 rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT,
3369 VTY_NEWLINE);
3370
3371 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3372 if ((rdistance = rn->info) != NULL)
3373 {
3374 if (header)
3375 {
3376 vty_out (vty, " Address Distance List%s",
3377 VTY_NEWLINE);
3378 header = 0;
3379 }
3380 sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
3381 vty_out (vty, " %-20s %4d %s%s",
3382 buf, rdistance->distance,
3383 rdistance->access_list ? rdistance->access_list : "",
3384 VTY_NEWLINE);
3385 }
3386}
3387
3388DEFUN (rip_distance,
3389 rip_distance_cmd,
3390 "distance <1-255>",
3391 "Administrative distance\n"
3392 "Distance value\n")
3393{
3394 rip->distance = atoi (argv[0]);
3395 return CMD_SUCCESS;
3396}
3397
3398DEFUN (no_rip_distance,
3399 no_rip_distance_cmd,
3400 "no distance <1-255>",
3401 NO_STR
3402 "Administrative distance\n"
3403 "Distance value\n")
3404{
3405 rip->distance = 0;
3406 return CMD_SUCCESS;
3407}
3408
3409DEFUN (rip_distance_source,
3410 rip_distance_source_cmd,
3411 "distance <1-255> A.B.C.D/M",
3412 "Administrative distance\n"
3413 "Distance value\n"
3414 "IP source prefix\n")
3415{
3416 rip_distance_set (vty, argv[0], argv[1], NULL);
3417 return CMD_SUCCESS;
3418}
3419
3420DEFUN (no_rip_distance_source,
3421 no_rip_distance_source_cmd,
3422 "no distance <1-255> A.B.C.D/M",
3423 NO_STR
3424 "Administrative distance\n"
3425 "Distance value\n"
3426 "IP source prefix\n")
3427{
3428 rip_distance_unset (vty, argv[0], argv[1], NULL);
3429 return CMD_SUCCESS;
3430}
3431
3432DEFUN (rip_distance_source_access_list,
3433 rip_distance_source_access_list_cmd,
3434 "distance <1-255> A.B.C.D/M WORD",
3435 "Administrative distance\n"
3436 "Distance value\n"
3437 "IP source prefix\n"
3438 "Access list name\n")
3439{
3440 rip_distance_set (vty, argv[0], argv[1], argv[2]);
3441 return CMD_SUCCESS;
3442}
3443
3444DEFUN (no_rip_distance_source_access_list,
3445 no_rip_distance_source_access_list_cmd,
3446 "no distance <1-255> A.B.C.D/M WORD",
3447 NO_STR
3448 "Administrative distance\n"
3449 "Distance value\n"
3450 "IP source prefix\n"
3451 "Access list name\n")
3452{
3453 rip_distance_unset (vty, argv[0], argv[1], argv[2]);
3454 return CMD_SUCCESS;
3455}
David Lamparter6b0655a2014-06-04 06:53:35 +02003456
Lu Feng0b74a0a2014-07-18 06:13:19 +00003457/* Update ECMP routes to zebra when ECMP is disabled. */
3458static void
3459rip_ecmp_disable (void)
3460{
3461 struct route_node *rp;
3462 struct rip_info *rinfo, *tmp_rinfo;
3463 struct list *list;
3464 struct listnode *node, *nextnode;
3465
3466 if (!rip)
3467 return;
3468
3469 for (rp = route_top (rip->table); rp; rp = route_next (rp))
3470 if ((list = rp->info) != NULL && listcount (list) > 1)
3471 {
3472 rinfo = listgetdata (listhead (list));
3473 if (!rip_route_rte (rinfo))
3474 continue;
3475
3476 /* Drop all other entries, except the first one. */
3477 for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
3478 if (tmp_rinfo != rinfo)
3479 {
3480 RIP_TIMER_OFF (tmp_rinfo->t_timeout);
3481 RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect);
3482 list_delete_node (list, node);
3483 rip_info_free (tmp_rinfo);
3484 }
3485
3486 /* Update zebra. */
3487 rip_zebra_ipv4_add (rp);
3488
3489 /* Set the route change flag. */
3490 SET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
3491
3492 /* Signal the output process to trigger an update. */
3493 rip_event (RIP_TRIGGERED_UPDATE, 0);
3494 }
3495}
3496
3497DEFUN (rip_allow_ecmp,
3498 rip_allow_ecmp_cmd,
3499 "allow-ecmp",
3500 "Allow Equal Cost MultiPath\n")
3501{
3502 if (rip->ecmp)
3503 {
3504 vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE);
3505 return CMD_WARNING;
3506 }
3507
3508 rip->ecmp = 1;
3509 zlog_info ("ECMP is enabled.");
3510 return CMD_SUCCESS;
3511}
3512
3513DEFUN (no_rip_allow_ecmp,
3514 no_rip_allow_ecmp_cmd,
3515 "no allow-ecmp",
3516 NO_STR
3517 "Allow Equal Cost MultiPath\n")
3518{
3519 if (!rip->ecmp)
3520 {
3521 vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE);
3522 return CMD_WARNING;
3523 }
3524
3525 rip->ecmp = 0;
3526 zlog_info ("ECMP is disabled.");
3527 rip_ecmp_disable ();
3528 return CMD_SUCCESS;
3529}
3530
paul718e3742002-12-13 20:15:29 +00003531/* Print out routes update time. */
pauldc63bfd2005-10-25 23:31:05 +00003532static void
paul718e3742002-12-13 20:15:29 +00003533rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo)
3534{
paul718e3742002-12-13 20:15:29 +00003535 time_t clock;
3536 struct tm *tm;
3537#define TIME_BUF 25
3538 char timebuf [TIME_BUF];
3539 struct thread *thread;
3540
paul718e3742002-12-13 20:15:29 +00003541 if ((thread = rinfo->t_timeout) != NULL)
3542 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003543 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003544 tm = gmtime (&clock);
3545 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3546 vty_out (vty, "%5s", timebuf);
3547 }
3548 else if ((thread = rinfo->t_garbage_collect) != NULL)
3549 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003550 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003551 tm = gmtime (&clock);
3552 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3553 vty_out (vty, "%5s", timebuf);
3554 }
3555}
3556
pauldc63bfd2005-10-25 23:31:05 +00003557static const char *
paul718e3742002-12-13 20:15:29 +00003558rip_route_type_print (int sub_type)
3559{
3560 switch (sub_type)
3561 {
3562 case RIP_ROUTE_RTE:
3563 return "n";
3564 case RIP_ROUTE_STATIC:
3565 return "s";
3566 case RIP_ROUTE_DEFAULT:
3567 return "d";
3568 case RIP_ROUTE_REDISTRIBUTE:
3569 return "r";
3570 case RIP_ROUTE_INTERFACE:
3571 return "i";
3572 default:
3573 return "?";
3574 }
3575}
3576
3577DEFUN (show_ip_rip,
3578 show_ip_rip_cmd,
3579 "show ip rip",
3580 SHOW_STR
3581 IP_STR
3582 "Show RIP routes\n")
3583{
3584 struct route_node *np;
Lu Fengb397cf42014-07-18 06:13:18 +00003585 struct rip_info *rinfo = NULL;
3586 struct list *list = NULL;
3587 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00003588
3589 if (! rip)
3590 return CMD_SUCCESS;
3591
hasso16705132003-05-25 14:49:19 +00003592 vty_out (vty, "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s"
3593 "Sub-codes:%s"
3594 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
paul718e3742002-12-13 20:15:29 +00003595 " (i) - interface%s%s"
hassoa1455d82004-03-03 19:36:24 +00003596 " Network Next Hop Metric From Tag Time%s",
hasso16705132003-05-25 14:49:19 +00003597 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003598
3599 for (np = route_top (rip->table); np; np = route_next (np))
Lu Fengb397cf42014-07-18 06:13:18 +00003600 if ((list = np->info) != NULL)
3601 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
paul718e3742002-12-13 20:15:29 +00003602 {
3603 int len;
3604
ajsf52d13c2005-10-01 17:38:06 +00003605 len = vty_out (vty, "%c(%s) %s/%d",
paul718e3742002-12-13 20:15:29 +00003606 /* np->lock, For debugging. */
ajsf52d13c2005-10-01 17:38:06 +00003607 zebra_route_char(rinfo->type),
paul718e3742002-12-13 20:15:29 +00003608 rip_route_type_print (rinfo->sub_type),
3609 inet_ntoa (np->p.u.prefix4), np->p.prefixlen);
3610
hassoa1455d82004-03-03 19:36:24 +00003611 len = 24 - len;
paul718e3742002-12-13 20:15:29 +00003612
3613 if (len > 0)
3614 vty_out (vty, "%*s", len, " ");
3615
3616 if (rinfo->nexthop.s_addr)
3617 vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop),
3618 rinfo->metric);
3619 else
3620 vty_out (vty, "0.0.0.0 %2d ", rinfo->metric);
3621
3622 /* Route which exist in kernel routing table. */
3623 if ((rinfo->type == ZEBRA_ROUTE_RIP) &&
3624 (rinfo->sub_type == RIP_ROUTE_RTE))
3625 {
3626 vty_out (vty, "%-15s ", inet_ntoa (rinfo->from));
hasso16705132003-05-25 14:49:19 +00003627 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003628 rip_vty_out_uptime (vty, rinfo);
3629 }
3630 else if (rinfo->metric == RIP_METRIC_INFINITY)
3631 {
3632 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003633 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003634 rip_vty_out_uptime (vty, rinfo);
3635 }
3636 else
hasso16705132003-05-25 14:49:19 +00003637 {
vincentfbf5d032005-09-29 11:25:50 +00003638 if (rinfo->external_metric)
3639 {
3640 len = vty_out (vty, "self (%s:%d)",
ajsf52d13c2005-10-01 17:38:06 +00003641 zebra_route_string(rinfo->type),
vincentfbf5d032005-09-29 11:25:50 +00003642 rinfo->external_metric);
3643 len = 16 - len;
3644 if (len > 0)
3645 vty_out (vty, "%*s", len, " ");
3646 }
3647 else
3648 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003649 vty_out (vty, "%3d", rinfo->tag);
3650 }
paul718e3742002-12-13 20:15:29 +00003651
3652 vty_out (vty, "%s", VTY_NEWLINE);
3653 }
3654 return CMD_SUCCESS;
3655}
3656
hasso16705132003-05-25 14:49:19 +00003657/* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */
3658DEFUN (show_ip_rip_status,
3659 show_ip_rip_status_cmd,
3660 "show ip rip status",
paul718e3742002-12-13 20:15:29 +00003661 SHOW_STR
3662 IP_STR
hasso16705132003-05-25 14:49:19 +00003663 "Show RIP routes\n"
paul718e3742002-12-13 20:15:29 +00003664 "IP routing protocol process parameters and statistics\n")
3665{
hasso52dc7ee2004-09-23 19:18:23 +00003666 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00003667 struct interface *ifp;
3668 struct rip_interface *ri;
Stephen Hemminger1423c802008-08-14 17:59:25 +01003669 extern const struct message ri_version_msg[];
hasso8a676be2004-10-08 06:36:38 +00003670 const char *send_version;
3671 const char *receive_version;
paul718e3742002-12-13 20:15:29 +00003672
3673 if (! rip)
3674 return CMD_SUCCESS;
3675
3676 vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE);
3677 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
3678 rip->update_time);
Andrew J. Schorra4c64822007-03-21 18:57:38 +00003679 vty_out (vty, " next due in %lu seconds%s",
3680 thread_timer_remain_second(rip->t_update),
paul718e3742002-12-13 20:15:29 +00003681 VTY_NEWLINE);
3682 vty_out (vty, " Timeout after %ld seconds,", rip->timeout_time);
3683 vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time,
3684 VTY_NEWLINE);
3685
3686 /* Filtering status show. */
3687 config_show_distribute (vty);
3688
3689 /* Default metric information. */
3690 vty_out (vty, " Default redistribution metric is %d%s",
3691 rip->default_metric, VTY_NEWLINE);
3692
3693 /* Redistribute information. */
3694 vty_out (vty, " Redistributing:");
3695 config_write_rip_redistribute (vty, 0);
3696 vty_out (vty, "%s", VTY_NEWLINE);
3697
paulf38a4712003-06-07 01:10:00 +00003698 vty_out (vty, " Default version control: send version %s,",
3699 lookup(ri_version_msg,rip->version_send));
3700 if (rip->version_recv == RI_RIP_VERSION_1_AND_2)
3701 vty_out (vty, " receive any version %s", VTY_NEWLINE);
3702 else
3703 vty_out (vty, " receive version %s %s",
3704 lookup(ri_version_msg,rip->version_recv), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003705
3706 vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE);
3707
paul1eb8ef22005-04-07 07:30:20 +00003708 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00003709 {
paul718e3742002-12-13 20:15:29 +00003710 ri = ifp->info;
3711
Stephen Hemminger82f5ee12009-04-07 15:00:46 -07003712 if (!ri->running)
3713 continue;
3714
paul718e3742002-12-13 20:15:29 +00003715 if (ri->enable_network || ri->enable_interface)
3716 {
3717 if (ri->ri_send == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003718 send_version = lookup (ri_version_msg, rip->version_send);
paul718e3742002-12-13 20:15:29 +00003719 else
3720 send_version = lookup (ri_version_msg, ri->ri_send);
3721
3722 if (ri->ri_receive == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003723 receive_version = lookup (ri_version_msg, rip->version_recv);
paul718e3742002-12-13 20:15:29 +00003724 else
3725 receive_version = lookup (ri_version_msg, ri->ri_receive);
3726
3727 vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name,
3728 send_version,
3729 receive_version,
3730 ri->key_chain ? ri->key_chain : "",
3731 VTY_NEWLINE);
3732 }
3733 }
3734
3735 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
3736 config_write_rip_network (vty, 0);
3737
paul4aaff3f2003-06-07 01:04:45 +00003738 {
3739 int found_passive = 0;
paul1eb8ef22005-04-07 07:30:20 +00003740 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul4aaff3f2003-06-07 01:04:45 +00003741 {
paul4aaff3f2003-06-07 01:04:45 +00003742 ri = ifp->info;
3743
3744 if ((ri->enable_network || ri->enable_interface) && ri->passive)
3745 {
3746 if (!found_passive)
3747 {
3748 vty_out (vty, " Passive Interface(s):%s", VTY_NEWLINE);
3749 found_passive = 1;
3750 }
3751 vty_out (vty, " %s%s", ifp->name, VTY_NEWLINE);
3752 }
3753 }
3754 }
3755
paul718e3742002-12-13 20:15:29 +00003756 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
3757 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
3758 rip_peer_display (vty);
3759
3760 rip_distance_show (vty);
3761
3762 return CMD_SUCCESS;
3763}
3764
3765/* RIP configuration write function. */
pauldc63bfd2005-10-25 23:31:05 +00003766static int
paul718e3742002-12-13 20:15:29 +00003767config_write_rip (struct vty *vty)
3768{
3769 int write = 0;
3770 struct route_node *rn;
3771 struct rip_distance *rdistance;
3772
3773 if (rip)
3774 {
3775 /* Router RIP statement. */
3776 vty_out (vty, "router rip%s", VTY_NEWLINE);
3777 write++;
3778
3779 /* RIP version statement. Default is RIP version 2. */
paulf38a4712003-06-07 01:10:00 +00003780 if (rip->version_send != RI_RIP_VERSION_2
3781 || rip->version_recv != RI_RIP_VERSION_1_AND_2)
3782 vty_out (vty, " version %d%s", rip->version_send,
paul718e3742002-12-13 20:15:29 +00003783 VTY_NEWLINE);
3784
3785 /* RIP timer configuration. */
3786 if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT
3787 || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT
3788 || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT)
3789 vty_out (vty, " timers basic %lu %lu %lu%s",
3790 rip->update_time,
3791 rip->timeout_time,
3792 rip->garbage_time,
3793 VTY_NEWLINE);
3794
3795 /* Default information configuration. */
3796 if (rip->default_information)
3797 {
3798 if (rip->default_information_route_map)
3799 vty_out (vty, " default-information originate route-map %s%s",
3800 rip->default_information_route_map, VTY_NEWLINE);
3801 else
3802 vty_out (vty, " default-information originate%s",
3803 VTY_NEWLINE);
3804 }
3805
3806 /* Redistribute configuration. */
3807 config_write_rip_redistribute (vty, 1);
3808
3809 /* RIP offset-list configuration. */
3810 config_write_rip_offset_list (vty);
3811
3812 /* RIP enabled network and interface configuration. */
3813 config_write_rip_network (vty, 1);
3814
3815 /* RIP default metric configuration */
3816 if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT)
3817 vty_out (vty, " default-metric %d%s",
3818 rip->default_metric, VTY_NEWLINE);
3819
3820 /* Distribute configuration. */
3821 write += config_write_distribute (vty);
3822
hasso16705132003-05-25 14:49:19 +00003823 /* Interface routemap configuration */
3824 write += config_write_if_rmap (vty);
3825
paul718e3742002-12-13 20:15:29 +00003826 /* Distance configuration. */
3827 if (rip->distance)
3828 vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE);
3829
3830 /* RIP source IP prefix distance configuration. */
3831 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3832 if ((rdistance = rn->info) != NULL)
3833 vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance,
3834 inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
3835 rdistance->access_list ? rdistance->access_list : "",
3836 VTY_NEWLINE);
3837
Lu Feng0b74a0a2014-07-18 06:13:19 +00003838 /* ECMP configuration. */
3839 if (rip->ecmp)
3840 vty_out (vty, " allow-ecmp%s", VTY_NEWLINE);
3841
paul718e3742002-12-13 20:15:29 +00003842 /* RIP static route configuration. */
3843 for (rn = route_top (rip->route); rn; rn = route_next (rn))
3844 if (rn->info)
3845 vty_out (vty, " route %s/%d%s",
3846 inet_ntoa (rn->p.u.prefix4),
3847 rn->p.prefixlen,
3848 VTY_NEWLINE);
3849
3850 }
3851 return write;
3852}
3853
3854/* RIP node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -08003855static struct cmd_node rip_node =
paul718e3742002-12-13 20:15:29 +00003856{
3857 RIP_NODE,
3858 "%s(config-router)# ",
3859 1
3860};
David Lamparter6b0655a2014-06-04 06:53:35 +02003861
paul718e3742002-12-13 20:15:29 +00003862/* Distribute-list update functions. */
pauldc63bfd2005-10-25 23:31:05 +00003863static void
paul718e3742002-12-13 20:15:29 +00003864rip_distribute_update (struct distribute *dist)
3865{
3866 struct interface *ifp;
3867 struct rip_interface *ri;
3868 struct access_list *alist;
3869 struct prefix_list *plist;
3870
3871 if (! dist->ifname)
3872 return;
3873
3874 ifp = if_lookup_by_name (dist->ifname);
3875 if (ifp == NULL)
3876 return;
3877
3878 ri = ifp->info;
3879
3880 if (dist->list[DISTRIBUTE_IN])
3881 {
3882 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
3883 if (alist)
3884 ri->list[RIP_FILTER_IN] = alist;
3885 else
3886 ri->list[RIP_FILTER_IN] = NULL;
3887 }
3888 else
3889 ri->list[RIP_FILTER_IN] = NULL;
3890
3891 if (dist->list[DISTRIBUTE_OUT])
3892 {
3893 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
3894 if (alist)
3895 ri->list[RIP_FILTER_OUT] = alist;
3896 else
3897 ri->list[RIP_FILTER_OUT] = NULL;
3898 }
3899 else
3900 ri->list[RIP_FILTER_OUT] = NULL;
3901
3902 if (dist->prefix[DISTRIBUTE_IN])
3903 {
3904 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
3905 if (plist)
3906 ri->prefix[RIP_FILTER_IN] = plist;
3907 else
3908 ri->prefix[RIP_FILTER_IN] = NULL;
3909 }
3910 else
3911 ri->prefix[RIP_FILTER_IN] = NULL;
3912
3913 if (dist->prefix[DISTRIBUTE_OUT])
3914 {
3915 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
3916 if (plist)
3917 ri->prefix[RIP_FILTER_OUT] = plist;
3918 else
3919 ri->prefix[RIP_FILTER_OUT] = NULL;
3920 }
3921 else
3922 ri->prefix[RIP_FILTER_OUT] = NULL;
3923}
3924
3925void
3926rip_distribute_update_interface (struct interface *ifp)
3927{
3928 struct distribute *dist;
3929
3930 dist = distribute_lookup (ifp->name);
3931 if (dist)
3932 rip_distribute_update (dist);
3933}
3934
3935/* Update all interface's distribute list. */
paul02ff83c2004-06-11 11:27:03 +00003936/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003937static void
paul02ff83c2004-06-11 11:27:03 +00003938rip_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00003939{
3940 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003941 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00003942
paul1eb8ef22005-04-07 07:30:20 +00003943 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3944 rip_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00003945}
paul11dde9c2004-05-31 14:00:00 +00003946/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003947static void
paul11dde9c2004-05-31 14:00:00 +00003948rip_distribute_update_all_wrapper(struct access_list *notused)
3949{
paul02ff83c2004-06-11 11:27:03 +00003950 rip_distribute_update_all(NULL);
paul11dde9c2004-05-31 14:00:00 +00003951}
David Lamparter6b0655a2014-06-04 06:53:35 +02003952
paul718e3742002-12-13 20:15:29 +00003953/* Delete all added rip route. */
3954void
paul216565a2005-10-25 23:35:28 +00003955rip_clean (void)
paul718e3742002-12-13 20:15:29 +00003956{
3957 int i;
3958 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00003959 struct rip_info *rinfo = NULL;
3960 struct list *list = NULL;
3961 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00003962
3963 if (rip)
3964 {
3965 /* Clear RIP routes */
3966 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00003967 if ((list = rp->info) != NULL)
3968 {
3969 rinfo = listgetdata (listhead (list));
3970 if (rip_route_rte (rinfo))
3971 rip_zebra_ipv4_delete (rp);
paul718e3742002-12-13 20:15:29 +00003972
Lu Fengb397cf42014-07-18 06:13:18 +00003973 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
3974 {
3975 RIP_TIMER_OFF (rinfo->t_timeout);
3976 RIP_TIMER_OFF (rinfo->t_garbage_collect);
3977 rip_info_free (rinfo);
3978 }
3979 list_delete (list);
3980 rp->info = NULL;
3981 route_unlock_node (rp);
3982 }
paul718e3742002-12-13 20:15:29 +00003983
3984 /* Cancel RIP related timers. */
3985 RIP_TIMER_OFF (rip->t_update);
3986 RIP_TIMER_OFF (rip->t_triggered_update);
3987 RIP_TIMER_OFF (rip->t_triggered_interval);
3988
3989 /* Cancel read thread. */
3990 if (rip->t_read)
3991 {
3992 thread_cancel (rip->t_read);
3993 rip->t_read = NULL;
3994 }
3995
3996 /* Close RIP socket. */
3997 if (rip->sock >= 0)
3998 {
3999 close (rip->sock);
4000 rip->sock = -1;
4001 }
4002
4003 /* Static RIP route configuration. */
4004 for (rp = route_top (rip->route); rp; rp = route_next (rp))
4005 if (rp->info)
4006 {
4007 rp->info = NULL;
4008 route_unlock_node (rp);
4009 }
4010
4011 /* RIP neighbor configuration. */
4012 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
4013 if (rp->info)
4014 {
4015 rp->info = NULL;
4016 route_unlock_node (rp);
4017 }
4018
4019 /* Redistribute related clear. */
4020 if (rip->default_information_route_map)
4021 free (rip->default_information_route_map);
4022
4023 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
4024 if (rip->route_map[i].name)
4025 free (rip->route_map[i].name);
4026
4027 XFREE (MTYPE_ROUTE_TABLE, rip->table);
4028 XFREE (MTYPE_ROUTE_TABLE, rip->route);
4029 XFREE (MTYPE_ROUTE_TABLE, rip->neighbor);
4030
4031 XFREE (MTYPE_RIP, rip);
4032 rip = NULL;
4033 }
4034
4035 rip_clean_network ();
paul4aaff3f2003-06-07 01:04:45 +00004036 rip_passive_nondefault_clean ();
paul718e3742002-12-13 20:15:29 +00004037 rip_offset_clean ();
4038 rip_interface_clean ();
4039 rip_distance_reset ();
4040 rip_redistribute_clean ();
4041}
4042
4043/* Reset all values to the default settings. */
4044void
paul216565a2005-10-25 23:35:28 +00004045rip_reset (void)
paul718e3742002-12-13 20:15:29 +00004046{
4047 /* Reset global counters. */
4048 rip_global_route_changes = 0;
4049 rip_global_queries = 0;
4050
4051 /* Call ripd related reset functions. */
4052 rip_debug_reset ();
4053 rip_route_map_reset ();
4054
4055 /* Call library reset functions. */
4056 vty_reset ();
4057 access_list_reset ();
4058 prefix_list_reset ();
4059
4060 distribute_list_reset ();
4061
4062 rip_interface_reset ();
4063 rip_distance_reset ();
4064
4065 rip_zclient_reset ();
4066}
4067
pauldc63bfd2005-10-25 23:31:05 +00004068static void
hasso16705132003-05-25 14:49:19 +00004069rip_if_rmap_update (struct if_rmap *if_rmap)
4070{
4071 struct interface *ifp;
4072 struct rip_interface *ri;
4073 struct route_map *rmap;
4074
4075 ifp = if_lookup_by_name (if_rmap->ifname);
4076 if (ifp == NULL)
4077 return;
4078
4079 ri = ifp->info;
4080
4081 if (if_rmap->routemap[IF_RMAP_IN])
4082 {
4083 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
4084 if (rmap)
4085 ri->routemap[IF_RMAP_IN] = rmap;
4086 else
4087 ri->routemap[IF_RMAP_IN] = NULL;
4088 }
4089 else
4090 ri->routemap[RIP_FILTER_IN] = NULL;
4091
4092 if (if_rmap->routemap[IF_RMAP_OUT])
4093 {
4094 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
4095 if (rmap)
4096 ri->routemap[IF_RMAP_OUT] = rmap;
4097 else
4098 ri->routemap[IF_RMAP_OUT] = NULL;
4099 }
4100 else
4101 ri->routemap[RIP_FILTER_OUT] = NULL;
4102}
4103
4104void
4105rip_if_rmap_update_interface (struct interface *ifp)
4106{
4107 struct if_rmap *if_rmap;
4108
4109 if_rmap = if_rmap_lookup (ifp->name);
4110 if (if_rmap)
4111 rip_if_rmap_update (if_rmap);
4112}
4113
pauldc63bfd2005-10-25 23:31:05 +00004114static void
hasso16705132003-05-25 14:49:19 +00004115rip_routemap_update_redistribute (void)
4116{
4117 int i;
4118
4119 if (rip)
4120 {
4121 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
4122 {
4123 if (rip->route_map[i].name)
4124 rip->route_map[i].map =
4125 route_map_lookup_by_name (rip->route_map[i].name);
4126 }
4127 }
4128}
4129
paul11dde9c2004-05-31 14:00:00 +00004130/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00004131static void
hasso98b718a2004-10-11 12:57:57 +00004132rip_routemap_update (const char *notused)
hasso16705132003-05-25 14:49:19 +00004133{
4134 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00004135 struct listnode *node, *nnode;
hasso16705132003-05-25 14:49:19 +00004136
paul1eb8ef22005-04-07 07:30:20 +00004137 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
4138 rip_if_rmap_update_interface (ifp);
hasso16705132003-05-25 14:49:19 +00004139
4140 rip_routemap_update_redistribute ();
4141}
4142
paul718e3742002-12-13 20:15:29 +00004143/* Allocate new rip structure and set default value. */
4144void
pauldc63bfd2005-10-25 23:31:05 +00004145rip_init (void)
paul718e3742002-12-13 20:15:29 +00004146{
4147 /* Randomize for triggered update random(). */
4148 srand (time (NULL));
4149
4150 /* Install top nodes. */
4151 install_node (&rip_node, config_write_rip);
4152
4153 /* Install rip commands. */
4154 install_element (VIEW_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00004155 install_element (VIEW_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00004156 install_element (ENABLE_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00004157 install_element (ENABLE_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00004158 install_element (CONFIG_NODE, &router_rip_cmd);
4159 install_element (CONFIG_NODE, &no_router_rip_cmd);
4160
4161 install_default (RIP_NODE);
4162 install_element (RIP_NODE, &rip_version_cmd);
4163 install_element (RIP_NODE, &no_rip_version_cmd);
4164 install_element (RIP_NODE, &no_rip_version_val_cmd);
4165 install_element (RIP_NODE, &rip_default_metric_cmd);
4166 install_element (RIP_NODE, &no_rip_default_metric_cmd);
4167 install_element (RIP_NODE, &no_rip_default_metric_val_cmd);
4168 install_element (RIP_NODE, &rip_timers_cmd);
4169 install_element (RIP_NODE, &no_rip_timers_cmd);
hasso16705132003-05-25 14:49:19 +00004170 install_element (RIP_NODE, &no_rip_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00004171 install_element (RIP_NODE, &rip_route_cmd);
4172 install_element (RIP_NODE, &no_rip_route_cmd);
4173 install_element (RIP_NODE, &rip_distance_cmd);
4174 install_element (RIP_NODE, &no_rip_distance_cmd);
4175 install_element (RIP_NODE, &rip_distance_source_cmd);
4176 install_element (RIP_NODE, &no_rip_distance_source_cmd);
4177 install_element (RIP_NODE, &rip_distance_source_access_list_cmd);
4178 install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd);
Lu Feng0b74a0a2014-07-18 06:13:19 +00004179 install_element (RIP_NODE, &rip_allow_ecmp_cmd);
4180 install_element (RIP_NODE, &no_rip_allow_ecmp_cmd);
paul718e3742002-12-13 20:15:29 +00004181
4182 /* Debug related init. */
4183 rip_debug_init ();
4184
paul718e3742002-12-13 20:15:29 +00004185 /* SNMP init. */
4186#ifdef HAVE_SNMP
4187 rip_snmp_init ();
4188#endif /* HAVE_SNMP */
4189
4190 /* Access list install. */
4191 access_list_init ();
paul11dde9c2004-05-31 14:00:00 +00004192 access_list_add_hook (rip_distribute_update_all_wrapper);
4193 access_list_delete_hook (rip_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00004194
4195 /* Prefix list initialize.*/
4196 prefix_list_init ();
4197 prefix_list_add_hook (rip_distribute_update_all);
4198 prefix_list_delete_hook (rip_distribute_update_all);
4199
4200 /* Distribute list install. */
4201 distribute_list_init (RIP_NODE);
4202 distribute_list_add_hook (rip_distribute_update);
4203 distribute_list_delete_hook (rip_distribute_update);
4204
hasso16705132003-05-25 14:49:19 +00004205 /* Route-map */
4206 rip_route_map_init ();
4207 rip_offset_init ();
4208
4209 route_map_add_hook (rip_routemap_update);
4210 route_map_delete_hook (rip_routemap_update);
4211
4212 if_rmap_init (RIP_NODE);
4213 if_rmap_hook_add (rip_if_rmap_update);
4214 if_rmap_hook_delete (rip_if_rmap_update);
4215
paul718e3742002-12-13 20:15:29 +00004216 /* Distance control. */
4217 rip_distance_table = route_table_init ();
4218}