/src/frr/pimd/pim_hello.c
Line  | Count  | Source  | 
1  |  | // SPDX-License-Identifier: GPL-2.0-or-later  | 
2  |  | /*  | 
3  |  |  * PIM for Quagga  | 
4  |  |  * Copyright (C) 2008  Everton da Silva Marques  | 
5  |  |  */  | 
6  |  |  | 
7  |  | #include <zebra.h>  | 
8  |  |  | 
9  |  | #include "log.h"  | 
10  |  | #include "if.h"  | 
11  |  |  | 
12  |  | #include "pimd.h"  | 
13  |  | #include "pim_instance.h"  | 
14  |  | #include "pim_pim.h"  | 
15  |  | #include "pim_str.h"  | 
16  |  | #include "pim_tlv.h"  | 
17  |  | #include "pim_util.h"  | 
18  |  | #include "pim_hello.h"  | 
19  |  | #include "pim_iface.h"  | 
20  |  | #include "pim_neighbor.h"  | 
21  |  | #include "pim_upstream.h"  | 
22  |  | #include "pim_bsm.h"  | 
23  |  |  | 
24  |  | static void on_trace(const char *label, struct interface *ifp, pim_addr src)  | 
25  | 0  | { | 
26  | 0  |   if (PIM_DEBUG_PIM_TRACE)  | 
27  | 0  |     zlog_debug("%s: from %pPAs on %s", label, &src, ifp->name); | 
28  | 0  | }  | 
29  |  |  | 
30  |  | static void tlv_trace_bool(const char *label, const char *tlv_name,  | 
31  |  |          const char *ifname, pim_addr src_addr, int isset,  | 
32  |  |          int value)  | 
33  | 0  | { | 
34  | 0  |   if (isset)  | 
35  | 0  |     zlog_debug(  | 
36  | 0  |       "%s: PIM hello option from %pPAs on interface %s: %s=%d",  | 
37  | 0  |       label, &src_addr, ifname, tlv_name, value);  | 
38  | 0  | }  | 
39  |  |  | 
40  |  | static void tlv_trace_uint16(const char *label, const char *tlv_name,  | 
41  |  |            const char *ifname, pim_addr src_addr, int isset,  | 
42  |  |            uint16_t value)  | 
43  | 0  | { | 
44  | 0  |   if (isset)  | 
45  | 0  |     zlog_debug(  | 
46  | 0  |       "%s: PIM hello option from %pPAs on interface %s: %s=%u",  | 
47  | 0  |       label, &src_addr, ifname, tlv_name, value);  | 
48  | 0  | }  | 
49  |  |  | 
50  |  | static void tlv_trace_uint32(const char *label, const char *tlv_name,  | 
51  |  |            const char *ifname, pim_addr src_addr, int isset,  | 
52  |  |            uint32_t value)  | 
53  | 0  | { | 
54  | 0  |   if (isset)  | 
55  | 0  |     zlog_debug(  | 
56  | 0  |       "%s: PIM hello option from %pPAs on interface %s: %s=%u",  | 
57  | 0  |       label, &src_addr, ifname, tlv_name, value);  | 
58  | 0  | }  | 
59  |  |  | 
60  |  | static void tlv_trace_uint32_hex(const char *label, const char *tlv_name,  | 
61  |  |          const char *ifname, pim_addr src_addr,  | 
62  |  |          int isset, uint32_t value)  | 
63  | 0  | { | 
64  | 0  |   if (isset)  | 
65  | 0  |     zlog_debug(  | 
66  | 0  |       "%s: PIM hello option from %pPAs on interface %s: %s=%08x",  | 
67  | 0  |       label, &src_addr, ifname, tlv_name, value);  | 
68  | 0  | }  | 
69  |  |  | 
70  |  | static void tlv_trace_list(const char *label, const char *tlv_name,  | 
71  |  |          const char *ifname, pim_addr src_addr, int isset,  | 
72  |  |          struct list *addr_list)  | 
73  | 0  | { | 
74  | 0  |   if (isset)  | 
75  | 0  |     zlog_debug(  | 
76  | 0  |       "%s: PIM hello option from %pPAs on interface %s: %s size=%d list=%p",  | 
77  | 0  |       label, &src_addr, ifname, tlv_name,  | 
78  | 0  |       addr_list ? ((int)listcount(addr_list)) : -1,  | 
79  | 0  |       (void *)addr_list);  | 
80  | 0  | }  | 
81  |  |  | 
82  |  | #define FREE_ADDR_LIST                                                         \  | 
83  | 89  |   if (hello_option_addr_list) {                                          \ | 
84  | 12  |     list_delete(&hello_option_addr_list);                          \  | 
85  | 12  |   }  | 
86  |  |  | 
87  |  | #define FREE_ADDR_LIST_THEN_RETURN(code)                                       \  | 
88  | 89  |   {                                                                      \ | 
89  | 89  |     FREE_ADDR_LIST                                                 \  | 
90  | 89  |     return (code);                                                 \  | 
91  | 89  |   }  | 
92  |  |  | 
93  |  | int pim_hello_recv(struct interface *ifp, pim_addr src_addr, uint8_t *tlv_buf,  | 
94  |  |        int tlv_buf_size)  | 
95  | 469  | { | 
96  | 469  |   struct pim_interface *pim_ifp;  | 
97  | 469  |   struct pim_neighbor *neigh;  | 
98  | 469  |   uint8_t *tlv_curr;  | 
99  | 469  |   uint8_t *tlv_pastend;  | 
100  | 469  |   pim_hello_options hello_options =  | 
101  | 469  |     0; /* bit array recording options found */  | 
102  | 469  |   uint16_t hello_option_holdtime = 0;  | 
103  | 469  |   uint16_t hello_option_propagation_delay = 0;  | 
104  | 469  |   uint16_t hello_option_override_interval = 0;  | 
105  | 469  |   uint32_t hello_option_dr_priority = 0;  | 
106  | 469  |   uint32_t hello_option_generation_id = 0;  | 
107  | 469  |   struct list *hello_option_addr_list = 0;  | 
108  |  |  | 
109  | 469  |   if (PIM_DEBUG_PIM_HELLO)  | 
110  | 0  |     on_trace(__func__, ifp, src_addr);  | 
111  |  |  | 
112  | 469  |   pim_ifp = ifp->info;  | 
113  | 469  |   assert(pim_ifp);  | 
114  |  |  | 
115  | 469  |   if (pim_ifp->pim_passive_enable) { | 
116  | 0  |     if (PIM_DEBUG_PIM_PACKETS)  | 
117  | 0  |       zlog_debug(  | 
118  | 0  |         "skip receiving PIM message on passive interface %s",  | 
119  | 0  |         ifp->name);  | 
120  | 0  |     return 0;  | 
121  | 0  |   }  | 
122  |  |  | 
123  | 469  |   ++pim_ifp->pim_ifstat_hello_recv;  | 
124  |  |  | 
125  |  |   /*  | 
126  |  |     Parse PIM hello TLVs  | 
127  |  |    */  | 
128  | 469  |   assert(tlv_buf_size >= 0);  | 
129  | 469  |   tlv_curr = tlv_buf;  | 
130  | 469  |   tlv_pastend = tlv_buf + tlv_buf_size;  | 
131  |  |  | 
132  | 3.75k  |   while (tlv_curr < tlv_pastend) { | 
133  | 3.43k  |     uint16_t option_type;  | 
134  | 3.43k  |     uint16_t option_len;  | 
135  | 3.43k  |     int remain = tlv_pastend - tlv_curr;  | 
136  |  |  | 
137  | 3.43k  |     if (remain < PIM_TLV_MIN_SIZE) { | 
138  | 5  |       if (PIM_DEBUG_PIM_HELLO)  | 
139  | 0  |         zlog_debug(  | 
140  | 5  |           "%s: short PIM hello TLV size=%d < min=%d from %pPAs on interface %s",  | 
141  | 5  |           __func__, remain, PIM_TLV_MIN_SIZE,  | 
142  | 5  |           &src_addr, ifp->name);  | 
143  | 5  |       FREE_ADDR_LIST_THEN_RETURN(-1);  | 
144  | 0  |     }  | 
145  |  |  | 
146  | 3.43k  |     option_type = PIM_TLV_GET_TYPE(tlv_curr);  | 
147  | 3.43k  |     tlv_curr += PIM_TLV_TYPE_SIZE;  | 
148  | 3.43k  |     option_len = PIM_TLV_GET_LENGTH(tlv_curr);  | 
149  | 3.43k  |     tlv_curr += PIM_TLV_LENGTH_SIZE;  | 
150  |  |  | 
151  | 3.43k  |     if ((tlv_curr + option_len) > tlv_pastend) { | 
152  | 14  |       if (PIM_DEBUG_PIM_HELLO)  | 
153  | 0  |         zlog_debug(  | 
154  | 14  |           "%s: long PIM hello TLV type=%d length=%d > left=%td from %pPAs on interface %s",  | 
155  | 14  |           __func__, option_type, option_len,  | 
156  | 14  |           tlv_pastend - tlv_curr, &src_addr,  | 
157  | 14  |           ifp->name);  | 
158  | 14  |       FREE_ADDR_LIST_THEN_RETURN(-2);  | 
159  | 0  |     }  | 
160  |  |  | 
161  | 3.41k  |     if (PIM_DEBUG_PIM_HELLO)  | 
162  | 0  |       zlog_debug(  | 
163  | 3.41k  |         "%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %pPAs on %s",  | 
164  | 3.41k  |         __func__, remain, option_type, option_len,  | 
165  | 3.41k  |         &src_addr, ifp->name);  | 
166  |  |  | 
167  | 3.41k  |     switch (option_type) { | 
168  | 217  |     case PIM_MSG_OPTION_TYPE_HOLDTIME:  | 
169  | 217  |       if (pim_tlv_parse_holdtime(ifp->name, src_addr,  | 
170  | 217  |                &hello_options,  | 
171  | 217  |                &hello_option_holdtime,  | 
172  | 217  |                option_len, tlv_curr)) { | 
173  | 8  |         FREE_ADDR_LIST_THEN_RETURN(-3);  | 
174  | 0  |       }  | 
175  | 209  |       break;  | 
176  | 464  |     case PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY:  | 
177  | 464  |       if (pim_tlv_parse_lan_prune_delay(  | 
178  | 464  |             ifp->name, src_addr, &hello_options,  | 
179  | 464  |             &hello_option_propagation_delay,  | 
180  | 464  |             &hello_option_override_interval, option_len,  | 
181  | 464  |             tlv_curr)) { | 
182  | 22  |         FREE_ADDR_LIST_THEN_RETURN(-4);  | 
183  | 0  |       }  | 
184  | 442  |       break;  | 
185  | 442  |     case PIM_MSG_OPTION_TYPE_DR_PRIORITY:  | 
186  | 328  |       if (pim_tlv_parse_dr_priority(ifp->name, src_addr,  | 
187  | 328  |                   &hello_options,  | 
188  | 328  |                   &hello_option_dr_priority,  | 
189  | 328  |                   option_len, tlv_curr)) { | 
190  | 24  |         FREE_ADDR_LIST_THEN_RETURN(-5);  | 
191  | 0  |       }  | 
192  | 304  |       break;  | 
193  | 494  |     case PIM_MSG_OPTION_TYPE_GENERATION_ID:  | 
194  | 494  |       if (pim_tlv_parse_generation_id(  | 
195  | 494  |             ifp->name, src_addr, &hello_options,  | 
196  | 494  |             &hello_option_generation_id, option_len,  | 
197  | 494  |             tlv_curr)) { | 
198  | 16  |         FREE_ADDR_LIST_THEN_RETURN(-6);  | 
199  | 0  |       }  | 
200  | 478  |       break;  | 
201  | 1.36k  |     case PIM_MSG_OPTION_TYPE_ADDRESS_LIST:  | 
202  | 1.36k  |       if (pim_tlv_parse_addr_list(ifp->name, src_addr,  | 
203  | 1.36k  |                 &hello_options,  | 
204  | 1.36k  |                 &hello_option_addr_list,  | 
205  | 1.36k  |                 option_len, tlv_curr)) { | 
206  | 60  |         return -7;  | 
207  | 60  |       }  | 
208  | 1.30k  |       break;  | 
209  | 1.30k  |     case PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH:  | 
210  | 0  |       if (PIM_DEBUG_PIM_HELLO)  | 
211  | 0  |         zlog_debug(  | 
212  | 0  |           "%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %pPAs on interface %s",  | 
213  | 0  |           __func__, option_type, option_len,  | 
214  | 0  |           &src_addr, ifp->name);  | 
215  | 0  |       break;  | 
216  | 547  |     default:  | 
217  | 547  |       if (PIM_DEBUG_PIM_HELLO)  | 
218  | 0  |         zlog_debug(  | 
219  | 3.41k  |           "%s: ignoring unknown PIM hello TLV type=%d length=%d from %pPAs on interface %s",  | 
220  | 3.41k  |           __func__, option_type, option_len,  | 
221  | 3.41k  |           &src_addr, ifp->name);  | 
222  | 3.41k  |     }  | 
223  |  |  | 
224  | 3.28k  |     tlv_curr += option_len;  | 
225  | 3.28k  |   }  | 
226  |  |  | 
227  |  |   /*  | 
228  |  |     Check received PIM hello options  | 
229  |  |   */  | 
230  |  |  | 
231  | 320  |   if (PIM_DEBUG_PIM_HELLO) { | 
232  | 0  |     tlv_trace_uint16(__func__, "holdtime", ifp->name, src_addr,  | 
233  | 0  |          PIM_OPTION_IS_SET(hello_options,  | 
234  | 0  |                PIM_OPTION_MASK_HOLDTIME),  | 
235  | 0  |          hello_option_holdtime);  | 
236  | 0  |     tlv_trace_uint16(  | 
237  | 0  |       __func__, "propagation_delay", ifp->name, src_addr,  | 
238  | 0  |       PIM_OPTION_IS_SET(hello_options,  | 
239  | 0  |             PIM_OPTION_MASK_LAN_PRUNE_DELAY),  | 
240  | 0  |       hello_option_propagation_delay);  | 
241  | 0  |     tlv_trace_uint16(  | 
242  | 0  |       __func__, "override_interval", ifp->name, src_addr,  | 
243  | 0  |       PIM_OPTION_IS_SET(hello_options,  | 
244  | 0  |             PIM_OPTION_MASK_LAN_PRUNE_DELAY),  | 
245  | 0  |       hello_option_override_interval);  | 
246  | 0  |     tlv_trace_bool(  | 
247  | 0  |       __func__, "can_disable_join_suppression", ifp->name,  | 
248  | 0  |       src_addr,  | 
249  | 0  |       PIM_OPTION_IS_SET(hello_options,  | 
250  | 0  |             PIM_OPTION_MASK_LAN_PRUNE_DELAY),  | 
251  | 0  |       PIM_OPTION_IS_SET(  | 
252  | 0  |         hello_options,  | 
253  | 0  |         PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION));  | 
254  | 0  |     tlv_trace_uint32(__func__, "dr_priority", ifp->name, src_addr,  | 
255  | 0  |          PIM_OPTION_IS_SET(hello_options,  | 
256  | 0  |                PIM_OPTION_MASK_DR_PRIORITY),  | 
257  | 0  |          hello_option_dr_priority);  | 
258  | 0  |     tlv_trace_uint32_hex(  | 
259  | 0  |       __func__, "generation_id", ifp->name, src_addr,  | 
260  | 0  |       PIM_OPTION_IS_SET(hello_options,  | 
261  | 0  |             PIM_OPTION_MASK_GENERATION_ID),  | 
262  | 0  |       hello_option_generation_id);  | 
263  | 0  |     tlv_trace_list(__func__, "address_list", ifp->name, src_addr,  | 
264  | 0  |              PIM_OPTION_IS_SET(hello_options,  | 
265  | 0  |              PIM_OPTION_MASK_ADDRESS_LIST),  | 
266  | 0  |              hello_option_addr_list);  | 
267  | 0  |   }  | 
268  |  |  | 
269  | 320  |   if (!PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) { | 
270  | 311  |     if (PIM_DEBUG_PIM_HELLO)  | 
271  | 0  |       zlog_debug(  | 
272  | 311  |         "%s: PIM hello missing holdtime from %pPAs on interface %s",  | 
273  | 311  |         __func__, &src_addr, ifp->name);  | 
274  | 311  |   }  | 
275  |  |  | 
276  |  |   /*  | 
277  |  |     New neighbor?  | 
278  |  |   */  | 
279  |  |  | 
280  | 320  |   neigh = pim_neighbor_find(ifp, src_addr, false);  | 
281  | 320  |   if (!neigh) { | 
282  |  |     /* Add as new neighbor */  | 
283  |  |  | 
284  | 146  |     neigh = pim_neighbor_add(  | 
285  | 146  |       ifp, src_addr, hello_options, hello_option_holdtime,  | 
286  | 146  |       hello_option_propagation_delay,  | 
287  | 146  |       hello_option_override_interval,  | 
288  | 146  |       hello_option_dr_priority, hello_option_generation_id,  | 
289  | 146  |       hello_option_addr_list, PIM_NEIGHBOR_SEND_DELAY);  | 
290  | 146  |     if (!neigh) { | 
291  | 0  |       if (PIM_DEBUG_PIM_HELLO)  | 
292  | 0  |         zlog_warn(  | 
293  | 0  |           "%s: failure creating PIM neighbor %pPAs on interface %s",  | 
294  | 0  |           __func__, &src_addr, ifp->name);  | 
295  | 0  |       FREE_ADDR_LIST_THEN_RETURN(-8);  | 
296  | 0  |     }  | 
297  |  |     /* Forward BSM if required */  | 
298  | 146  |     if (!pim_bsm_new_nbr_fwd(neigh, ifp)) { | 
299  | 146  |       if (PIM_DEBUG_PIM_HELLO)  | 
300  | 0  |         zlog_debug(  | 
301  | 146  |           "%s: forwarding bsm to new nbr failed",  | 
302  | 146  |           __func__);  | 
303  | 146  |     }  | 
304  |  |  | 
305  |  |     /* actual addr list has been saved under neighbor */  | 
306  | 146  |     return 0;  | 
307  | 146  |   }  | 
308  |  |  | 
309  |  |   /*  | 
310  |  |     Received generation ID ?  | 
311  |  |   */  | 
312  |  |  | 
313  | 174  |   if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_GENERATION_ID)) { | 
314  |  |     /* GenID mismatch ? */  | 
315  | 75  |     if (!PIM_OPTION_IS_SET(neigh->hello_options,  | 
316  | 75  |                PIM_OPTION_MASK_GENERATION_ID)  | 
317  | 71  |         || (hello_option_generation_id != neigh->generation_id)) { | 
318  |  |       /* GenID mismatch, then replace neighbor */  | 
319  |  |  | 
320  | 71  |       if (PIM_DEBUG_PIM_HELLO)  | 
321  | 0  |         zlog_debug(  | 
322  | 71  |           "%s: GenId mismatch new=%08x old=%08x: replacing neighbor %pPAs on %s",  | 
323  | 71  |           __func__, hello_option_generation_id,  | 
324  | 71  |           neigh->generation_id, &src_addr,  | 
325  | 71  |           ifp->name);  | 
326  |  |  | 
327  | 71  |       pim_upstream_rpf_genid_changed(pim_ifp->pim,  | 
328  | 71  |                    neigh->source_addr);  | 
329  |  |  | 
330  | 71  |       pim_neighbor_delete(ifp, neigh, "GenID mismatch");  | 
331  | 71  |       neigh = pim_neighbor_add(ifp, src_addr, hello_options,  | 
332  | 71  |              hello_option_holdtime,  | 
333  | 71  |              hello_option_propagation_delay,  | 
334  | 71  |              hello_option_override_interval,  | 
335  | 71  |              hello_option_dr_priority,  | 
336  | 71  |              hello_option_generation_id,  | 
337  | 71  |              hello_option_addr_list,  | 
338  | 71  |              PIM_NEIGHBOR_SEND_NOW);  | 
339  | 71  |       if (!neigh) { | 
340  | 0  |         if (PIM_DEBUG_PIM_HELLO)  | 
341  | 0  |           zlog_debug(  | 
342  | 0  |             "%s: failure re-creating PIM neighbor %pPAs on interface %s",  | 
343  | 0  |             __func__, &src_addr, ifp->name);  | 
344  | 0  |         FREE_ADDR_LIST_THEN_RETURN(-9);  | 
345  | 0  |       }  | 
346  |  |       /* Forward BSM if required */  | 
347  | 71  |       if (!pim_bsm_new_nbr_fwd(neigh, ifp)) { | 
348  | 71  |         if (PIM_DEBUG_PIM_HELLO)  | 
349  | 0  |           zlog_debug(  | 
350  | 71  |             "%s: forwarding bsm to new nbr failed",  | 
351  | 71  |             __func__);  | 
352  | 71  |       }  | 
353  |  |       /* actual addr list is saved under neighbor */  | 
354  | 71  |       return 0;  | 
355  |  |  | 
356  | 71  |     } /* GenId mismatch: replace neighbor */  | 
357  |  |  | 
358  | 75  |   } /* GenId received */  | 
359  |  |  | 
360  |  |   /*  | 
361  |  |     Update existing neighbor  | 
362  |  |   */  | 
363  |  |  | 
364  | 103  |   pim_neighbor_update(neigh, hello_options, hello_option_holdtime,  | 
365  | 103  |           hello_option_dr_priority, hello_option_addr_list);  | 
366  |  |   /* actual addr list is saved under neighbor */  | 
367  | 103  |   return 0;  | 
368  | 174  | }  | 
369  |  |  | 
370  |  | int pim_hello_build_tlv(struct interface *ifp, uint8_t *tlv_buf,  | 
371  |  |       int tlv_buf_size, uint16_t holdtime,  | 
372  |  |       uint32_t dr_priority, uint32_t generation_id,  | 
373  |  |       uint16_t propagation_delay, uint16_t override_interval,  | 
374  |  |       int can_disable_join_suppression)  | 
375  | 161  | { | 
376  | 161  |   uint8_t *curr = tlv_buf;  | 
377  | 161  |   uint8_t *pastend = tlv_buf + tlv_buf_size;  | 
378  | 161  |   uint8_t *tmp;  | 
379  | 161  | #if PIM_IPV == 4  | 
380  | 161  |   struct pim_interface *pim_ifp = ifp->info;  | 
381  | 161  |   struct pim_instance *pim = pim_ifp->pim;  | 
382  | 161  | #endif  | 
383  |  |  | 
384  |  |   /*  | 
385  |  |    * Append options  | 
386  |  |    */  | 
387  |  |  | 
388  |  |   /* Holdtime */  | 
389  | 161  |   curr = pim_tlv_append_uint16(curr, pastend,  | 
390  | 161  |              PIM_MSG_OPTION_TYPE_HOLDTIME, holdtime);  | 
391  | 161  |   if (!curr) { | 
392  | 0  |     if (PIM_DEBUG_PIM_HELLO) { | 
393  | 0  |       zlog_debug(  | 
394  | 0  |         "%s: could not set PIM hello Holdtime option for interface %s",  | 
395  | 0  |         __func__, ifp->name);  | 
396  | 0  |     }  | 
397  | 0  |     return -1;  | 
398  | 0  |   }  | 
399  |  |  | 
400  |  |   /* LAN Prune Delay */  | 
401  | 161  |   tmp = pim_tlv_append_2uint16(curr, pastend,  | 
402  | 161  |              PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY,  | 
403  | 161  |              propagation_delay, override_interval);  | 
404  | 161  |   if (!tmp) { | 
405  | 0  |     if (PIM_DEBUG_PIM_HELLO) { | 
406  | 0  |       zlog_debug(  | 
407  | 0  |         "%s: could not set PIM LAN Prune Delay option for interface %s",  | 
408  | 0  |         __func__, ifp->name);  | 
409  | 0  |     }  | 
410  | 0  |     return -1;  | 
411  | 0  |   }  | 
412  | 161  |   if (can_disable_join_suppression) { | 
413  | 0  |     *(curr + 4) |= 0x80; /* enable T bit */  | 
414  | 0  |   }  | 
415  | 161  |   curr = tmp;  | 
416  |  |  | 
417  |  |   /* DR Priority */  | 
418  | 161  |   curr = pim_tlv_append_uint32(  | 
419  | 161  |     curr, pastend, PIM_MSG_OPTION_TYPE_DR_PRIORITY, dr_priority);  | 
420  | 161  |   if (!curr) { | 
421  | 0  |     if (PIM_DEBUG_PIM_HELLO) { | 
422  | 0  |       zlog_debug(  | 
423  | 0  |         "%s: could not set PIM hello DR Priority option for interface %s",  | 
424  | 0  |         __func__, ifp->name);  | 
425  | 0  |     }  | 
426  | 0  |     return -2;  | 
427  | 0  |   }  | 
428  |  |  | 
429  |  |   /* Generation ID */  | 
430  | 161  |   curr = pim_tlv_append_uint32(curr, pastend,  | 
431  | 161  |              PIM_MSG_OPTION_TYPE_GENERATION_ID,  | 
432  | 161  |              generation_id);  | 
433  | 161  |   if (!curr) { | 
434  | 0  |     if (PIM_DEBUG_PIM_HELLO) { | 
435  | 0  |       zlog_debug(  | 
436  | 0  |         "%s: could not set PIM hello Generation ID option for interface %s",  | 
437  | 0  |         __func__, ifp->name);  | 
438  | 0  |     }  | 
439  | 0  |     return -3;  | 
440  | 0  |   }  | 
441  |  |  | 
442  |  |   /* Secondary Address List */  | 
443  | 161  |   if (ifp->connected->count) { | 
444  | 161  |     curr = pim_tlv_append_addrlist_ucast(curr, pastend, ifp,  | 
445  | 161  |                  PIM_AF);  | 
446  | 161  |     if (!curr) { | 
447  | 0  |       if (PIM_DEBUG_PIM_HELLO) { | 
448  | 0  |         zlog_debug(  | 
449  | 0  |           "%s: could not set PIM hello %s Secondary Address List option for interface %s",  | 
450  | 0  |           __func__, PIM_AF_NAME, ifp->name);  | 
451  | 0  |       }  | 
452  | 0  |       return -4;  | 
453  | 0  |     }  | 
454  | 161  | #if PIM_IPV == 4  | 
455  | 161  |     if (pim->send_v6_secondary) { | 
456  | 161  |       curr = pim_tlv_append_addrlist_ucast(curr, pastend, ifp,  | 
457  | 161  |                    AF_INET6);  | 
458  | 161  |       if (!curr) { | 
459  | 0  |         if (PIM_DEBUG_PIM_HELLO) { | 
460  | 0  |           zlog_debug(  | 
461  | 0  |             "%s: could not sent PIM hello v6 secondary Address List option for interface %s",  | 
462  | 0  |             __func__, ifp->name);  | 
463  | 0  |         }  | 
464  | 0  |         return -4;  | 
465  | 0  |       }  | 
466  | 161  |     }  | 
467  | 161  | #endif  | 
468  | 161  |   }  | 
469  |  |  | 
470  | 161  |   return curr - tlv_buf;  | 
471  | 161  | }  | 
472  |  |  | 
473  |  | /*  | 
474  |  |   RFC 4601: 4.3.1.  Sending Hello Messages  | 
475  |  |  | 
476  |  |   Thus, if a router needs to send a Join/Prune or Assert message on an  | 
477  |  |   interface on which it has not yet sent a Hello message with the  | 
478  |  |   currently configured IP address, then it MUST immediately send the  | 
479  |  |   relevant Hello message without waiting for the Hello Timer to  | 
480  |  |   expire, followed by the Join/Prune or Assert message.  | 
481  |  | */  | 
482  |  | void pim_hello_require(struct interface *ifp)  | 
483  | 669  | { | 
484  | 669  |   struct pim_interface *pim_ifp;  | 
485  |  |  | 
486  | 669  |   assert(ifp);  | 
487  |  |  | 
488  | 669  |   pim_ifp = ifp->info;  | 
489  |  |  | 
490  | 669  |   assert(pim_ifp);  | 
491  |  |  | 
492  | 669  |   if (PIM_IF_FLAG_TEST_HELLO_SENT(pim_ifp->flags))  | 
493  | 579  |     return;  | 
494  |  |  | 
495  | 90  |   pim_hello_restart_now(ifp); /* Send hello and restart timer */  | 
496  | 90  | }  |