]> git.sommitrealweird.co.uk Git - quagga-debian.git/blob - zebra/zebra_rnh.c
Merge tag 'upstream/1.2.3'
[quagga-debian.git] / zebra / zebra_rnh.c
1 /* Zebra next hop tracking code
2  * Copyright (C) 2013 Cumulus Networks, Inc.
3  *
4  * This file is part of GNU Zebra.
5  *
6  * GNU Zebra is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation; either version 2, or (at your option) any
9  * later version.
10  *
11  * GNU Zebra is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
18  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19  * 02111-1307, USA.
20  */
21
22 #include <zebra.h>
23
24 #include "prefix.h"
25 #include "table.h"
26 #include "memory.h"
27 #include "str.h"
28 #include "command.h"
29 #include "if.h"
30 #include "log.h"
31 #include "sockunion.h"
32 #include "linklist.h"
33 #include "thread.h"
34 #include "workqueue.h"
35 #include "prefix.h"
36 #include "routemap.h"
37 #include "stream.h"
38 #include "nexthop.h"
39
40 #include "zebra/rib.h"
41 #include "zebra/rt.h"
42 #include "zebra/zserv.h"
43 #include "zebra/redistribute.h"
44 #include "zebra/debug.h"
45 #include "zebra/zebra_rnh.h"
46
47 #define lookup_rnh_table(v, f)                   \
48 ({                                               \
49   struct zebra_vrf *zvrf;                        \
50   struct route_table *t = NULL;                  \
51   zvrf = zebra_vrf_lookup(v);                    \
52   if (zvrf)                                      \
53     t = zvrf->rnh_table[family2afi(f)];          \
54   t;                                             \
55 })
56
57 static void free_state(struct rib *rib);
58 static void copy_state(struct rnh *rnh, struct rib *rib);
59 static int compare_state(struct rib *r1, struct rib *r2);
60 static int send_client(struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id);
61 static void print_rnh(struct route_node *rn, struct vty *vty);
62
63 char *
64 rnh_str (struct rnh *rnh, char *buf, int size)
65 {
66   prefix2str(&(rnh->node->p), buf, size);
67   return buf;
68 }
69
70 struct rnh *
71 zebra_add_rnh (struct prefix *p, vrf_id_t vrfid)
72 {
73   struct route_table *table;
74   struct route_node *rn;
75   struct rnh *rnh = NULL;
76
77   if (IS_ZEBRA_DEBUG_NHT)
78     {
79       char buf[INET6_ADDRSTRLEN];
80       prefix2str(p, buf, INET6_ADDRSTRLEN);
81       zlog_debug("add rnh %s in vrf %d", buf, vrfid);
82     }
83   table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p));
84   if (!table)
85     {
86       zlog_debug("add_rnh: rnh table not found\n");
87       return NULL;
88     }
89
90   /* Make it sure prefixlen is applied to the prefix. */
91   apply_mask (p);
92
93   /* Lookup (or add) route node.*/
94   rn = route_node_get (table, p);
95
96   if (!rn->info)
97     {
98       rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh));
99       rnh->client_list = list_new();
100       route_lock_node (rn);
101       rn->info = rnh;
102       rnh->node = rn;
103     }
104
105   route_unlock_node (rn);
106   return (rn->info);
107 }
108
109 struct rnh *
110 zebra_lookup_rnh (struct prefix *p, vrf_id_t vrfid)
111 {
112   struct route_table *table;
113   struct route_node *rn;
114
115   table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p));
116   if (!table)
117     return NULL;
118
119   /* Make it sure prefixlen is applied to the prefix. */
120   apply_mask (p);
121
122   /* Lookup route node.*/
123   rn = route_node_lookup (table, p);
124   if (!rn)
125     return NULL;
126
127   route_unlock_node (rn);
128   return (rn->info);
129 }
130
131 void
132 zebra_delete_rnh (struct rnh *rnh)
133 {
134   struct route_node *rn;
135
136   if (!rnh || !(rn = rnh->node))
137     return;
138
139   if (IS_ZEBRA_DEBUG_NHT)
140     {
141       char buf[INET6_ADDRSTRLEN];
142       zlog_debug("delete rnh %s", rnh_str(rnh, buf, INET6_ADDRSTRLEN));
143     }
144
145   list_free(rnh->client_list);
146   free_state(rnh->state);
147   XFREE(MTYPE_RNH, rn->info);
148   rn->info = NULL;
149   route_unlock_node (rn);
150   return;
151 }
152
153 void
154 zebra_add_rnh_client (struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id)
155 {
156   if (IS_ZEBRA_DEBUG_NHT)
157     {
158       char buf[INET6_ADDRSTRLEN];
159       zlog_debug("client %s registers rnh %s",
160                  zebra_route_string(client->proto),
161                  rnh_str(rnh, buf, INET6_ADDRSTRLEN));
162     }
163   if (!listnode_lookup(rnh->client_list, client))
164     {
165       listnode_add(rnh->client_list, client);
166       send_client(rnh, client, vrf_id);
167     }
168 }
169
170 void
171 zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client)
172 {
173   if (IS_ZEBRA_DEBUG_NHT)
174     {
175       char buf[INET6_ADDRSTRLEN];
176       zlog_debug("client %s unregisters rnh %s",
177                  zebra_route_string(client->proto),
178                  rnh_str(rnh, buf, INET6_ADDRSTRLEN));
179     }
180   listnode_delete(rnh->client_list, client);
181   if (list_isempty(rnh->client_list))
182     zebra_delete_rnh(rnh);
183 }
184
185 int
186 zebra_evaluate_rnh_table (vrf_id_t vrfid, int family)
187 {
188   struct route_table *ptable;
189   struct route_table *ntable;
190   struct route_node *prn;
191   struct route_node *nrn;
192   struct rnh *rnh;
193   struct zserv *client;
194   struct listnode *node;
195   struct rib *rib;
196
197   ntable = lookup_rnh_table(vrfid, family);
198   if (!ntable)
199     {
200       zlog_debug("evaluate_rnh_table: rnh table not found\n");
201       return -1;
202     }
203
204   ptable = zebra_vrf_table(family2afi(family), SAFI_UNICAST, vrfid);
205   if (!ptable)
206     {
207       zlog_debug("evaluate_rnh_table: prefix table not found\n");
208       return -1;
209     }
210
211   for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
212     {
213       if (!nrn->info)
214           continue;
215       
216       rnh = nrn->info;
217       prn = route_node_match(ptable, &nrn->p);
218       if (!prn)
219         rib = NULL;
220       else
221         {
222           RNODE_FOREACH_RIB(prn, rib)
223             {
224               if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
225                 continue;
226               if (! CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
227                 continue;
228
229               if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
230                 {
231                   if (rib->type == ZEBRA_ROUTE_CONNECT)
232                     break;
233
234                   if (rib->type == ZEBRA_ROUTE_NHRP)
235                     {
236                       struct nexthop *nexthop;
237                       for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
238                         if (nexthop->type == NEXTHOP_TYPE_IFINDEX ||
239                             nexthop->type == NEXTHOP_TYPE_IFNAME)
240                           break;
241                       if (nexthop)
242                         break;
243                     }
244                 }
245               else
246                 break;
247             }
248         }
249
250       if (compare_state(rib, rnh->state))
251         {
252           if (IS_ZEBRA_DEBUG_NHT)
253             {
254               char bufn[INET6_ADDRSTRLEN];
255               char bufp[INET6_ADDRSTRLEN];
256               prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
257               if (prn)
258                 prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN);
259               else
260                 strcpy(bufp, "null");
261               zlog_debug("rnh %s resolved through route %s - sending "
262                          "nexthop %s event to clients", bufn, bufp,
263                          rib ? "reachable" : "unreachable");
264             }
265           copy_state(rnh, rib);
266           for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
267             send_client(rnh, client, vrfid);
268         }
269     }
270   return 1;
271 }
272
273 int
274 zebra_dispatch_rnh_table (vrf_id_t vrfid, int family, struct zserv *client)
275 {
276   struct route_table *ntable;
277   struct route_node *nrn;
278   struct rnh *rnh;
279
280   ntable = lookup_rnh_table(vrfid, family);
281   if (!ntable)
282     {
283       zlog_debug("dispatch_rnh_table: rnh table not found\n");
284       return -1;
285     }
286
287   for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
288     {
289       if (!nrn->info)
290           continue;
291
292       rnh = nrn->info;
293       if (IS_ZEBRA_DEBUG_NHT)
294         {
295           char bufn[INET6_ADDRSTRLEN];
296           prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
297           zlog_debug("rnh %s - sending nexthop %s event to client %s", bufn,
298                      rnh->state ? "reachable" : "unreachable",
299                      zebra_route_string(client->proto));
300         }
301       send_client(rnh, client, vrfid);
302     }
303   return 1;
304 }
305
306 void
307 zebra_print_rnh_table (vrf_id_t vrfid, int af, struct vty *vty)
308 {
309   struct route_table *table;
310   struct route_node *rn;
311
312   table = lookup_rnh_table(vrfid, af);
313   if (!table)
314     {
315       zlog_debug("print_rnhs: rnh table not found\n");
316       return;
317     }
318
319   for (rn = route_top(table); rn; rn = route_next(rn))
320       if (rn->info)
321         print_rnh(rn, vty);
322 }
323
324 int
325 zebra_cleanup_rnh_client (vrf_id_t vrfid, int family, struct zserv *client)
326 {
327   struct route_table *ntable;
328   struct route_node *nrn;
329   struct rnh *rnh;
330
331   ntable = lookup_rnh_table(vrfid, family);
332   if (!ntable)
333     {
334       zlog_debug("cleanup_rnh_client: rnh table not found\n");
335       return -1;
336     }
337
338   for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
339     {
340       if (!nrn->info)
341           continue;
342
343       rnh = nrn->info;
344       if (IS_ZEBRA_DEBUG_NHT)
345         {
346           char bufn[INET6_ADDRSTRLEN];
347           prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
348           zlog_debug("rnh %s - cleaning state for client %s", bufn,
349                      zebra_route_string(client->proto));
350         }
351       zebra_remove_rnh_client(rnh, client);
352     }
353   return 1;
354 }
355
356 /**
357  * free_state - free up the rib structure associated with the rnh.
358  */
359 static void
360 free_state (struct rib *rib)
361 {
362   struct nexthop *nexthop, *next;
363
364   if (!rib)
365     return;
366
367   /* free RIB and nexthops */
368   for (nexthop = rib->nexthop; nexthop; nexthop = next)
369     {
370       next = nexthop->next;
371       nexthop_free (nexthop);
372     }
373   XFREE (MTYPE_RIB, rib);
374 }
375
376 /**
377  * copy_nexthop - copy a nexthop to the rib structure.
378  */
379 static void
380 rib_copy_nexthop (struct rib *state, struct nexthop *nh)
381 {
382   struct nexthop *nexthop;
383
384   nexthop = nexthop_new();
385   nexthop->flags = nh->flags;
386   nexthop->type = nh->type;
387   nexthop->ifindex = nh->ifindex;
388   if (nh->ifname)
389     nexthop->ifname = XSTRDUP(0, nh->ifname);
390   memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr));
391   memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr));
392
393   rib_nexthop_add(state, nexthop);
394 }
395
396 static void
397 copy_state (struct rnh *rnh, struct rib *rib)
398 {
399   struct rib *state;
400   struct nexthop *nh;
401
402   if (rnh->state)
403     {
404       free_state(rnh->state);
405       rnh->state = NULL;
406     }
407
408   if (!rib)
409     return;
410
411   state = XCALLOC (MTYPE_RIB, sizeof (struct rib));
412   state->type = rib->type;
413   state->metric = rib->metric;
414
415   for (nh = rib->nexthop; nh; nh = nh->next)
416     rib_copy_nexthop(state, nh);
417   rnh->state = state;
418 }
419
420 static int
421 compare_state (struct rib *r1, struct rib *r2)
422 {
423   struct nexthop *nh1;
424   struct nexthop *nh2;
425   u_char found_nh = 0;
426
427   if (!r1 && !r2)
428     return 0;
429
430   if ((!r1 && r2) || (r1 && !r2))
431       return 1;
432
433   if (r1->metric != r2->metric)
434       return 1;
435
436   if (r1->nexthop_num != r2->nexthop_num)
437       return 1;
438
439   /* We need to verify that the nexthops for r1 match the nexthops for r2.
440    * Since it is possible for a rib entry to have the same nexthop multiple
441    * times (Example: [a,a]) we need to keep track of which r2 nexthops we have
442    * already used as a match against a r1 nexthop.  We track this
443    * via NEXTHOP_FLAG_MATCHED. Clear this flag for all r2 nexthops when you
444    * are finished.
445    *
446    * TRUE:  r1 [a,b], r2 [a,b]
447    * TRUE:  r1 [a,b], r2 [b,a]
448    * FALSE: r1 [a,b], r2 [a,c]
449    * FALSE: r1 [a,a], r2 [a,b]
450    */
451   for (nh1 = r1->nexthop; nh1; nh1 = nh1->next)
452     {
453       found_nh = 0;
454       for (nh2 = r2->nexthop; nh2; nh2 = nh2->next)
455         {
456           if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED))
457             continue;
458
459           if (nexthop_same_no_recurse(nh1, nh2))
460             {
461               SET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED);
462               found_nh = 1;
463               break;
464             }
465         }
466
467       if (!found_nh)
468         {
469           for (nh2 = r2->nexthop; nh2; nh2 = nh2->next)
470             if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED))
471               UNSET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED);
472           return 1;
473         }
474     }
475
476   for (nh2 = r2->nexthop; nh2; nh2 = nh2->next)
477     if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED))
478       UNSET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED);
479
480   return 0;
481 }
482
483 static int
484 send_client (struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id)
485 {
486   struct stream *s;
487   struct rib *rib;
488   unsigned long nump;
489   u_char num;
490   struct nexthop *nexthop;
491   struct route_node *rn;
492
493   rn = rnh->node;
494   rib = rnh->state;
495
496   /* Get output stream. */
497   s = client->obuf;
498   stream_reset (s);
499
500   zserv_create_header (s, ZEBRA_NEXTHOP_UPDATE, vrf_id);
501
502   stream_putw(s, rn->p.family);
503   stream_put_prefix (s, &rn->p);
504
505   if (rib)
506     {
507       stream_putl (s, rib->metric);
508       num = 0;
509       nump = stream_get_endp(s);
510       stream_putc (s, 0);
511       for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
512         if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) &&
513             ! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) &&
514             CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
515           {
516             stream_putc (s, nexthop->type);
517             switch (nexthop->type)
518               {
519               case ZEBRA_NEXTHOP_IPV4:
520                 stream_put_in_addr (s, &nexthop->gate.ipv4);
521                 break;
522               case ZEBRA_NEXTHOP_IFINDEX:
523               case ZEBRA_NEXTHOP_IFNAME:
524                 stream_putl (s, nexthop->ifindex);
525                 break;
526               case ZEBRA_NEXTHOP_IPV4_IFINDEX:
527               case ZEBRA_NEXTHOP_IPV4_IFNAME:
528                 stream_put_in_addr (s, &nexthop->gate.ipv4);
529                 stream_putl (s, nexthop->ifindex);
530                 break;
531 #ifdef HAVE_IPV6
532               case ZEBRA_NEXTHOP_IPV6:
533                 stream_put (s, &nexthop->gate.ipv6, 16);
534                 break;
535               case ZEBRA_NEXTHOP_IPV6_IFINDEX:
536               case ZEBRA_NEXTHOP_IPV6_IFNAME:
537                 stream_put (s, &nexthop->gate.ipv6, 16);
538                 stream_putl (s, nexthop->ifindex);
539                 break;
540 #endif /* HAVE_IPV6 */
541               default:
542                 /* do nothing */
543                 break;
544               }
545             num++;
546           }
547       stream_putc_at (s, nump, num);
548     }
549   else
550     {
551       stream_putl (s, 0);
552       stream_putc (s, 0);
553     }
554   stream_putw_at (s, 0, stream_get_endp (s));
555
556   client->nh_last_upd_time = quagga_time(NULL);
557   client->last_write_cmd = ZEBRA_NEXTHOP_UPDATE;
558   return zebra_server_send_message(client);
559 }
560
561 static void
562 print_nh (struct nexthop *nexthop, struct vty *vty)
563 {
564   char buf[BUFSIZ];
565
566   switch (nexthop->type)
567     {
568     case NEXTHOP_TYPE_IPV4:
569     case NEXTHOP_TYPE_IPV4_IFINDEX:
570       vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4));
571       if (nexthop->ifindex)
572         vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex));
573       break;
574     case NEXTHOP_TYPE_IPV6:
575     case NEXTHOP_TYPE_IPV6_IFINDEX:
576     case NEXTHOP_TYPE_IPV6_IFNAME:
577       vty_out (vty, " %s",
578                inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
579       if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
580         vty_out (vty, ", %s", nexthop->ifname);
581       else if (nexthop->ifindex)
582         vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex));
583       break;
584     case NEXTHOP_TYPE_IFINDEX:
585       vty_out (vty, " is directly connected, %s",
586                ifindex2ifname (nexthop->ifindex));
587       break;
588     case NEXTHOP_TYPE_IFNAME:
589       vty_out (vty, " is directly connected, %s", nexthop->ifname);
590       break;
591     case NEXTHOP_TYPE_BLACKHOLE:
592       vty_out (vty, " is directly connected, Null0");
593       break;
594     default:
595       break;
596     }
597   vty_out(vty, "%s", VTY_NEWLINE);
598 }
599
600 static void
601 print_rnh (struct route_node *rn, struct vty *vty)
602 {
603   struct rnh *rnh;
604   struct nexthop *nexthop;
605   struct listnode *node;
606   struct zserv *client;
607   char buf[BUFSIZ];
608
609   rnh = rn->info;
610   vty_out(vty, "%s%s", inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
611           VTY_NEWLINE);
612   if (rnh->state)
613     {
614       vty_out(vty, " resolved via %s%s",
615               zebra_route_string(rnh->state->type), VTY_NEWLINE);
616       for (nexthop = rnh->state->nexthop; nexthop; nexthop = nexthop->next)
617         print_nh(nexthop, vty);
618     }
619   else
620     vty_out(vty, " unresolved%s%s",
621             CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)" : "",
622             VTY_NEWLINE);
623
624   vty_out(vty, " Client list:");
625   for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
626     vty_out(vty, " %s(fd %d)", zebra_route_string(client->proto),
627             client->sock);
628   vty_out(vty, "%s", VTY_NEWLINE);
629 }