Line | Count | Source (jump to first uncovered line) |
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 "frrevent.h" |
11 | | #include "memory.h" |
12 | | #include "if.h" |
13 | | #include "network.h" |
14 | | |
15 | | #include "pimd.h" |
16 | | #include "pim_instance.h" |
17 | | #include "pim_pim.h" |
18 | | #include "pim_time.h" |
19 | | #include "pim_iface.h" |
20 | | #include "pim_sock.h" |
21 | | #include "pim_str.h" |
22 | | #include "pim_util.h" |
23 | | #include "pim_tlv.h" |
24 | | #include "pim_neighbor.h" |
25 | | #include "pim_hello.h" |
26 | | #include "pim_join.h" |
27 | | #include "pim_assert.h" |
28 | | #include "pim_msg.h" |
29 | | #include "pim_register.h" |
30 | | #include "pim_errors.h" |
31 | | #include "pim_bsm.h" |
32 | | #include <lib/lib_errors.h> |
33 | | |
34 | | static void on_pim_hello_send(struct event *t); |
35 | | |
36 | | static const char *pim_pim_msgtype2str(enum pim_msg_type type) |
37 | 0 | { |
38 | 0 | switch (type) { |
39 | 0 | case PIM_MSG_TYPE_HELLO: |
40 | 0 | return "HELLO"; |
41 | 0 | case PIM_MSG_TYPE_REGISTER: |
42 | 0 | return "REGISTER"; |
43 | 0 | case PIM_MSG_TYPE_REG_STOP: |
44 | 0 | return "REGSTOP"; |
45 | 0 | case PIM_MSG_TYPE_JOIN_PRUNE: |
46 | 0 | return "JOINPRUNE"; |
47 | 0 | case PIM_MSG_TYPE_BOOTSTRAP: |
48 | 0 | return "BOOT"; |
49 | 0 | case PIM_MSG_TYPE_ASSERT: |
50 | 0 | return "ASSERT"; |
51 | 0 | case PIM_MSG_TYPE_GRAFT: |
52 | 0 | return "GRAFT"; |
53 | 0 | case PIM_MSG_TYPE_GRAFT_ACK: |
54 | 0 | return "GACK"; |
55 | 0 | case PIM_MSG_TYPE_CANDIDATE: |
56 | 0 | return "CANDIDATE"; |
57 | 0 | } |
58 | 0 |
|
59 | 0 | return "UNKNOWN"; |
60 | 0 | } |
61 | | |
62 | | static void sock_close(struct interface *ifp) |
63 | 0 | { |
64 | 0 | struct pim_interface *pim_ifp = ifp->info; |
65 | |
|
66 | 0 | if (PIM_DEBUG_PIM_TRACE) { |
67 | 0 | if (pim_ifp->t_pim_sock_read) { |
68 | 0 | zlog_debug( |
69 | 0 | "Cancelling READ event for PIM socket fd=%d on interface %s", |
70 | 0 | pim_ifp->pim_sock_fd, ifp->name); |
71 | 0 | } |
72 | 0 | } |
73 | 0 | EVENT_OFF(pim_ifp->t_pim_sock_read); |
74 | |
|
75 | 0 | if (PIM_DEBUG_PIM_TRACE) { |
76 | 0 | if (pim_ifp->t_pim_hello_timer) { |
77 | 0 | zlog_debug( |
78 | 0 | "Cancelling PIM hello timer for interface %s", |
79 | 0 | ifp->name); |
80 | 0 | } |
81 | 0 | } |
82 | 0 | EVENT_OFF(pim_ifp->t_pim_hello_timer); |
83 | |
|
84 | 0 | if (PIM_DEBUG_PIM_TRACE) { |
85 | 0 | zlog_debug("Deleting PIM socket fd=%d on interface %s", |
86 | 0 | pim_ifp->pim_sock_fd, ifp->name); |
87 | 0 | } |
88 | | |
89 | | /* |
90 | | * If the fd is already deleted no need to do anything here |
91 | | */ |
92 | 0 | if (pim_ifp->pim_sock_fd > 0 && close(pim_ifp->pim_sock_fd)) { |
93 | 0 | zlog_warn( |
94 | 0 | "Failure closing PIM socket fd=%d on interface %s: errno=%d: %s", |
95 | 0 | pim_ifp->pim_sock_fd, ifp->name, errno, |
96 | 0 | safe_strerror(errno)); |
97 | 0 | } |
98 | |
|
99 | 0 | pim_ifp->pim_sock_fd = -1; |
100 | 0 | pim_ifp->pim_sock_creation = 0; |
101 | 0 | } |
102 | | |
103 | | void pim_sock_delete(struct interface *ifp, const char *delete_message) |
104 | 0 | { |
105 | 0 | zlog_info("PIM INTERFACE DOWN: on interface %s: %s", ifp->name, |
106 | 0 | delete_message); |
107 | |
|
108 | 0 | if (!ifp->info) { |
109 | 0 | flog_err(EC_PIM_CONFIG, |
110 | 0 | "%s: %s: but PIM not enabled on interface %s (!)", |
111 | 0 | __func__, delete_message, ifp->name); |
112 | 0 | return; |
113 | 0 | } |
114 | | |
115 | | /* |
116 | | RFC 4601: 4.3.1. Sending Hello Messages |
117 | | |
118 | | Before an interface goes down or changes primary IP address, a Hello |
119 | | message with a zero HoldTime should be sent immediately (with the |
120 | | old IP address if the IP address changed). |
121 | | */ |
122 | 0 | pim_hello_send(ifp, 0 /* zero-sec holdtime */); |
123 | |
|
124 | 0 | pim_neighbor_delete_all(ifp, delete_message); |
125 | |
|
126 | 0 | sock_close(ifp); |
127 | 0 | } |
128 | | |
129 | | /* For now check dst address for hello, assrt and join/prune is all pim rtr */ |
130 | | static bool pim_pkt_dst_addr_ok(enum pim_msg_type type, pim_addr addr) |
131 | 3.23k | { |
132 | 3.23k | if ((type == PIM_MSG_TYPE_HELLO) || (type == PIM_MSG_TYPE_ASSERT) |
133 | 3.23k | || (type == PIM_MSG_TYPE_JOIN_PRUNE)) { |
134 | 1.72k | if (pim_addr_cmp(addr, qpim_all_pim_routers_addr)) |
135 | 13 | return false; |
136 | 1.72k | } |
137 | | |
138 | 3.22k | return true; |
139 | 3.23k | } |
140 | | |
141 | | int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len, |
142 | | pim_sgaddr sg) |
143 | 3.27k | { |
144 | 3.27k | struct iovec iov[2], *iovp = iov; |
145 | 3.27k | #if PIM_IPV == 4 |
146 | 3.27k | struct ip *ip_hdr = (struct ip *)buf; |
147 | 3.27k | size_t ip_hlen; /* ip header length in bytes */ |
148 | 3.27k | #endif |
149 | 3.27k | uint8_t *pim_msg; |
150 | 3.27k | uint32_t pim_msg_len = 0; |
151 | 3.27k | uint16_t pim_checksum; /* received checksum */ |
152 | 3.27k | uint16_t checksum; /* computed checksum */ |
153 | 3.27k | struct pim_neighbor *neigh; |
154 | 3.27k | struct pim_msg_header *header; |
155 | 3.27k | bool no_fwd; |
156 | | |
157 | 3.27k | #if PIM_IPV == 4 |
158 | 3.27k | if (len <= sizeof(*ip_hdr)) { |
159 | 9 | if (PIM_DEBUG_PIM_PACKETS) |
160 | 0 | zlog_debug( |
161 | 9 | "PIM packet size=%zu shorter than minimum=%zu", |
162 | 9 | len, sizeof(*ip_hdr)); |
163 | 9 | return -1; |
164 | 9 | } |
165 | | |
166 | 3.26k | ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */ |
167 | 3.26k | #ifdef FUZZING |
168 | | /* |
169 | | * Ensure that the header length is 20 or 24 bytes as is appropriate |
170 | | * The kernel typically ensures that the passed up ip header meets |
171 | | * standards, and would actually drop the packet if it didn't meet |
172 | | * them. So since we are fuzzing and faking the header bits/bobs |
173 | | * then let's ensure that we don't get into a weird situation |
174 | | * where a bad ip_hlen here causes pim_msg_len to wrap around into |
175 | | * the high billions and then we have an issue later |
176 | | */ |
177 | 3.26k | if (ip_hlen != 20 && ip_hlen != 24) |
178 | 14 | return -1; |
179 | 3.24k | #endif |
180 | 3.24k | sg = pim_sgaddr_from_iphdr(ip_hdr); |
181 | | |
182 | 3.24k | pim_msg = buf + ip_hlen; |
183 | 3.24k | pim_msg_len = len - ip_hlen; |
184 | | #else |
185 | | struct ipv6_ph phdr = { |
186 | | .src = sg.src, |
187 | | .dst = sg.grp, |
188 | | .ulpl = htonl(len), |
189 | | .next_hdr = IPPROTO_PIM, |
190 | | }; |
191 | | |
192 | | iovp->iov_base = &phdr; |
193 | | iovp->iov_len = sizeof(phdr); |
194 | | iovp++; |
195 | | |
196 | | /* NB: header is not included in IPv6 RX */ |
197 | | pim_msg = buf; |
198 | | pim_msg_len = len; |
199 | | #endif |
200 | | |
201 | 3.24k | iovp->iov_base = pim_msg; |
202 | 3.24k | iovp->iov_len = pim_msg_len; |
203 | 3.24k | iovp++; |
204 | | |
205 | 3.24k | if (pim_msg_len < PIM_PIM_MIN_LEN) { |
206 | 7 | if (PIM_DEBUG_PIM_PACKETS) |
207 | 0 | zlog_debug( |
208 | 7 | "PIM message size=%d shorter than minimum=%d", |
209 | 7 | pim_msg_len, PIM_PIM_MIN_LEN); |
210 | 7 | return -1; |
211 | 7 | } |
212 | 3.24k | header = (struct pim_msg_header *)pim_msg; |
213 | | |
214 | 3.24k | if (header->ver != PIM_PROTO_VERSION) { |
215 | 5 | if (PIM_DEBUG_PIM_PACKETS) |
216 | 0 | zlog_debug( |
217 | 5 | "Ignoring PIM pkt from %s with unsupported version: %d", |
218 | 5 | ifp->name, header->ver); |
219 | 5 | return -1; |
220 | 5 | } |
221 | | |
222 | | /* save received checksum */ |
223 | 3.23k | pim_checksum = header->checksum; |
224 | | |
225 | | /* for computing checksum */ |
226 | 3.23k | header->checksum = 0; |
227 | 3.23k | no_fwd = header->Nbit; |
228 | | |
229 | 3.23k | if (header->type == PIM_MSG_TYPE_REGISTER) { |
230 | 152 | if (pim_msg_len < PIM_MSG_REGISTER_LEN) { |
231 | 3 | if (PIM_DEBUG_PIM_PACKETS) |
232 | 0 | zlog_debug("PIM Register Message size=%d shorther than min length %d", |
233 | 3 | pim_msg_len, PIM_MSG_REGISTER_LEN); |
234 | 3 | return -1; |
235 | 3 | } |
236 | | |
237 | | #if PIM_IPV == 6 |
238 | | phdr.ulpl = htonl(PIM_MSG_REGISTER_LEN); |
239 | | #endif |
240 | | /* First 8 byte header checksum */ |
241 | 149 | iovp[-1].iov_len = PIM_MSG_REGISTER_LEN; |
242 | 149 | checksum = in_cksumv(iov, iovp - iov); |
243 | | |
244 | 149 | if (checksum != pim_checksum) { |
245 | | #if PIM_IPV == 6 |
246 | | phdr.ulpl = htonl(pim_msg_len); |
247 | | #endif |
248 | 148 | iovp[-1].iov_len = pim_msg_len; |
249 | | |
250 | 148 | checksum = in_cksumv(iov, iovp - iov); |
251 | 148 | if (checksum != pim_checksum) { |
252 | 148 | if (PIM_DEBUG_PIM_PACKETS) |
253 | 0 | zlog_debug( |
254 | 148 | "Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x", |
255 | 148 | ifp->name, pim_checksum, |
256 | 148 | checksum); |
257 | | #ifndef FUZZING |
258 | | return -1; |
259 | | #endif |
260 | 148 | } |
261 | 148 | } |
262 | 3.08k | } else { |
263 | 3.08k | checksum = in_cksumv(iov, iovp - iov); |
264 | 3.08k | if (checksum != pim_checksum) { |
265 | 3.08k | if (PIM_DEBUG_PIM_PACKETS) |
266 | 0 | zlog_debug( |
267 | 3.08k | "Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x", |
268 | 3.08k | ifp->name, pim_checksum, checksum); |
269 | | #ifndef FUZZING |
270 | | return -1; |
271 | | #endif |
272 | 3.08k | } |
273 | 3.08k | } |
274 | | |
275 | 3.23k | if (PIM_DEBUG_PIM_PACKETS) { |
276 | 0 | zlog_debug( |
277 | 0 | "Recv PIM %s packet from %pPA to %pPA on %s: pim_version=%d pim_msg_size=%d checksum=%x", |
278 | 0 | pim_pim_msgtype2str(header->type), &sg.src, &sg.grp, |
279 | 0 | ifp->name, header->ver, pim_msg_len, checksum); |
280 | 0 | if (PIM_DEBUG_PIM_PACKETDUMP_RECV) |
281 | 0 | pim_pkt_dump(__func__, pim_msg, pim_msg_len); |
282 | 0 | } |
283 | | |
284 | 3.23k | if (!pim_pkt_dst_addr_ok(header->type, sg.grp)) { |
285 | 13 | zlog_warn( |
286 | 13 | "%s: Ignoring Pkt. Unexpected IP destination %pPA for %s (Expected: all_pim_routers_addr) from %pPA", |
287 | 13 | __func__, &sg.grp, pim_pim_msgtype2str(header->type), |
288 | 13 | &sg.src); |
289 | 13 | return -1; |
290 | 13 | } |
291 | | |
292 | 3.22k | switch (header->type) { |
293 | 616 | case PIM_MSG_TYPE_HELLO: |
294 | 616 | return pim_hello_recv(ifp, sg.src, pim_msg + PIM_MSG_HEADER_LEN, |
295 | 616 | pim_msg_len - PIM_MSG_HEADER_LEN); |
296 | 0 | break; |
297 | 149 | case PIM_MSG_TYPE_REGISTER: |
298 | 149 | return pim_register_recv(ifp, sg.grp, sg.src, |
299 | 149 | pim_msg + PIM_MSG_HEADER_LEN, |
300 | 149 | pim_msg_len - PIM_MSG_HEADER_LEN); |
301 | 0 | break; |
302 | 89 | case PIM_MSG_TYPE_REG_STOP: |
303 | 89 | return pim_register_stop_recv(ifp, pim_msg + PIM_MSG_HEADER_LEN, |
304 | 89 | pim_msg_len - PIM_MSG_HEADER_LEN); |
305 | 0 | break; |
306 | 883 | case PIM_MSG_TYPE_JOIN_PRUNE: |
307 | 883 | neigh = pim_neighbor_find(ifp, sg.src, false); |
308 | 883 | if (!neigh) { |
309 | 1 | if (PIM_DEBUG_PIM_PACKETS) |
310 | 0 | zlog_debug( |
311 | 1 | "%s %s: non-hello PIM message type=%d from non-neighbor %pPA on %s", |
312 | 1 | __FILE__, __func__, header->type, |
313 | 1 | &sg.src, ifp->name); |
314 | 1 | return -1; |
315 | 1 | } |
316 | 882 | pim_neighbor_timer_reset(neigh, neigh->holdtime); |
317 | 882 | return pim_joinprune_recv(ifp, neigh, sg.src, |
318 | 882 | pim_msg + PIM_MSG_HEADER_LEN, |
319 | 882 | pim_msg_len - PIM_MSG_HEADER_LEN); |
320 | 0 | break; |
321 | 211 | case PIM_MSG_TYPE_ASSERT: |
322 | 211 | neigh = pim_neighbor_find(ifp, sg.src, false); |
323 | 211 | if (!neigh) { |
324 | 2 | if (PIM_DEBUG_PIM_PACKETS) |
325 | 0 | zlog_debug( |
326 | 2 | "%s %s: non-hello PIM message type=%d from non-neighbor %pPA on %s", |
327 | 2 | __FILE__, __func__, header->type, |
328 | 2 | &sg.src, ifp->name); |
329 | 2 | return -1; |
330 | 2 | } |
331 | 209 | pim_neighbor_timer_reset(neigh, neigh->holdtime); |
332 | 209 | return pim_assert_recv(ifp, neigh, sg.src, |
333 | 209 | pim_msg + PIM_MSG_HEADER_LEN, |
334 | 209 | pim_msg_len - PIM_MSG_HEADER_LEN); |
335 | 0 | break; |
336 | 1.26k | case PIM_MSG_TYPE_BOOTSTRAP: |
337 | 1.26k | return pim_bsm_process(ifp, &sg, pim_msg, pim_msg_len, no_fwd); |
338 | 0 | break; |
339 | | |
340 | 7 | default: |
341 | 7 | if (PIM_DEBUG_PIM_PACKETS) { |
342 | 0 | zlog_debug( |
343 | 0 | "Recv PIM packet type %d which is not currently understood", |
344 | 0 | header->type); |
345 | 0 | } |
346 | 7 | return -1; |
347 | 3.22k | } |
348 | 3.22k | } |
349 | | |
350 | | static void pim_sock_read_on(struct interface *ifp); |
351 | | |
352 | | static void pim_sock_read(struct event *t) |
353 | 0 | { |
354 | 0 | struct interface *ifp, *orig_ifp; |
355 | 0 | struct pim_interface *pim_ifp; |
356 | 0 | int fd; |
357 | 0 | struct sockaddr_storage from; |
358 | 0 | struct sockaddr_storage to; |
359 | 0 | socklen_t fromlen = sizeof(from); |
360 | 0 | socklen_t tolen = sizeof(to); |
361 | 0 | uint8_t buf[PIM_PIM_BUFSIZE_READ]; |
362 | 0 | int len; |
363 | 0 | ifindex_t ifindex = -1; |
364 | 0 | int result = -1; /* defaults to bad */ |
365 | 0 | static long long count = 0; |
366 | 0 | int cont = 1; |
367 | 0 |
|
368 | 0 | orig_ifp = ifp = EVENT_ARG(t); |
369 | 0 | fd = EVENT_FD(t); |
370 | 0 |
|
371 | 0 | pim_ifp = ifp->info; |
372 | 0 |
|
373 | 0 | while (cont) { |
374 | 0 | pim_sgaddr sg; |
375 | 0 |
|
376 | 0 | len = pim_socket_recvfromto(fd, buf, sizeof(buf), &from, |
377 | 0 | &fromlen, &to, &tolen, &ifindex); |
378 | 0 | if (len < 0) { |
379 | 0 | if (errno == EINTR) |
380 | 0 | continue; |
381 | 0 | if (errno == EWOULDBLOCK || errno == EAGAIN) |
382 | 0 | break; |
383 | 0 |
|
384 | 0 | if (PIM_DEBUG_PIM_PACKETS) |
385 | 0 | zlog_debug("Received errno: %d %s", errno, |
386 | 0 | safe_strerror(errno)); |
387 | 0 | goto done; |
388 | 0 | } |
389 | 0 |
|
390 | 0 | /* |
391 | 0 | * What? So with vrf's the incoming packet is received |
392 | 0 | * on the vrf interface but recvfromto above returns |
393 | 0 | * the right ifindex, so just use it. We know |
394 | 0 | * it's the right interface because we bind to it |
395 | 0 | */ |
396 | 0 | ifp = if_lookup_by_index(ifindex, pim_ifp->pim->vrf->vrf_id); |
397 | 0 | if (!ifp || !ifp->info) { |
398 | 0 | if (PIM_DEBUG_PIM_PACKETS) |
399 | 0 | zlog_debug( |
400 | 0 | "%s: Received incoming pim packet on interface(%s:%d) not yet configured for pim", |
401 | 0 | __func__, ifp ? ifp->name : "Unknown", |
402 | 0 | ifindex); |
403 | 0 | goto done; |
404 | 0 | } |
405 | 0 | #if PIM_IPV == 4 |
406 | 0 | sg.src = ((struct sockaddr_in *)&from)->sin_addr; |
407 | 0 | sg.grp = ((struct sockaddr_in *)&to)->sin_addr; |
408 | 0 | #else |
409 | 0 | sg.src = ((struct sockaddr_in6 *)&from)->sin6_addr; |
410 | 0 | sg.grp = ((struct sockaddr_in6 *)&to)->sin6_addr; |
411 | 0 | #endif |
412 | 0 |
|
413 | 0 | int fail = pim_pim_packet(ifp, buf, len, sg); |
414 | 0 | if (fail) { |
415 | 0 | if (PIM_DEBUG_PIM_PACKETS) |
416 | 0 | zlog_debug("%s: pim_pim_packet() return=%d", |
417 | 0 | __func__, fail); |
418 | 0 | goto done; |
419 | 0 | } |
420 | 0 |
|
421 | 0 | count++; |
422 | 0 | if (count % router->packet_process == 0) |
423 | 0 | cont = 0; |
424 | 0 | } |
425 | 0 |
|
426 | 0 | result = 0; /* good */ |
427 | 0 |
|
428 | 0 | done: |
429 | 0 | pim_sock_read_on(orig_ifp); |
430 | 0 |
|
431 | 0 | if (result) { |
432 | 0 | ++pim_ifp->pim_ifstat_hello_recvfail; |
433 | 0 | } |
434 | 0 | } |
435 | | |
436 | | static void pim_sock_read_on(struct interface *ifp) |
437 | 0 | { |
438 | 0 | struct pim_interface *pim_ifp; |
439 | |
|
440 | 0 | assert(ifp); |
441 | 0 | assert(ifp->info); |
442 | | |
443 | 0 | pim_ifp = ifp->info; |
444 | |
|
445 | 0 | if (PIM_DEBUG_PIM_TRACE_DETAIL) { |
446 | 0 | zlog_debug("Scheduling READ event on PIM socket fd=%d", |
447 | 0 | pim_ifp->pim_sock_fd); |
448 | 0 | } |
449 | 0 | event_add_read(router->master, pim_sock_read, ifp, pim_ifp->pim_sock_fd, |
450 | 0 | &pim_ifp->t_pim_sock_read); |
451 | 0 | } |
452 | | |
453 | | static int pim_sock_open(struct interface *ifp) |
454 | 0 | { |
455 | 0 | int fd; |
456 | 0 | struct pim_interface *pim_ifp = ifp->info; |
457 | |
|
458 | 0 | fd = pim_socket_mcast(IPPROTO_PIM, pim_ifp->primary_address, ifp, |
459 | 0 | 0 /* loop=false */); |
460 | 0 | if (fd < 0) |
461 | 0 | return -1; |
462 | | |
463 | 0 | if (pim_socket_join(fd, qpim_all_pim_routers_addr, |
464 | 0 | pim_ifp->primary_address, ifp->ifindex, pim_ifp)) { |
465 | 0 | close(fd); |
466 | 0 | return -2; |
467 | 0 | } |
468 | | |
469 | 0 | return fd; |
470 | 0 | } |
471 | | |
472 | | void pim_ifstat_reset(struct interface *ifp) |
473 | 2 | { |
474 | 2 | struct pim_interface *pim_ifp; |
475 | | |
476 | 2 | assert(ifp); |
477 | | |
478 | 2 | pim_ifp = ifp->info; |
479 | 2 | if (!pim_ifp) { |
480 | 0 | return; |
481 | 0 | } |
482 | | |
483 | 2 | pim_ifp->pim_ifstat_start = pim_time_monotonic_sec(); |
484 | 2 | pim_ifp->pim_ifstat_hello_sent = 0; |
485 | 2 | pim_ifp->pim_ifstat_hello_sendfail = 0; |
486 | 2 | pim_ifp->pim_ifstat_hello_recv = 0; |
487 | 2 | pim_ifp->pim_ifstat_hello_recvfail = 0; |
488 | 2 | pim_ifp->pim_ifstat_bsm_rx = 0; |
489 | 2 | pim_ifp->pim_ifstat_bsm_tx = 0; |
490 | 2 | pim_ifp->pim_ifstat_join_recv = 0; |
491 | 2 | pim_ifp->pim_ifstat_join_send = 0; |
492 | 2 | pim_ifp->pim_ifstat_prune_recv = 0; |
493 | 2 | pim_ifp->pim_ifstat_prune_send = 0; |
494 | 2 | pim_ifp->pim_ifstat_reg_recv = 0; |
495 | 2 | pim_ifp->pim_ifstat_reg_send = 0; |
496 | 2 | pim_ifp->pim_ifstat_reg_stop_recv = 0; |
497 | 2 | pim_ifp->pim_ifstat_reg_stop_send = 0; |
498 | 2 | pim_ifp->pim_ifstat_assert_recv = 0; |
499 | 2 | pim_ifp->pim_ifstat_assert_send = 0; |
500 | 2 | pim_ifp->pim_ifstat_bsm_cfg_miss = 0; |
501 | 2 | pim_ifp->pim_ifstat_ucast_bsm_cfg_miss = 0; |
502 | 2 | pim_ifp->pim_ifstat_bsm_invalid_sz = 0; |
503 | 2 | pim_ifp->igmp_ifstat_joins_sent = 0; |
504 | 2 | pim_ifp->igmp_ifstat_joins_failed = 0; |
505 | 2 | pim_ifp->igmp_peak_group_count = 0; |
506 | 2 | } |
507 | | |
508 | | void pim_sock_reset(struct interface *ifp) |
509 | 2 | { |
510 | 2 | struct pim_interface *pim_ifp; |
511 | | |
512 | 2 | assert(ifp); |
513 | 2 | assert(ifp->info); |
514 | | |
515 | 2 | pim_ifp = ifp->info; |
516 | | |
517 | 2 | pim_ifp->primary_address = pim_find_primary_addr(ifp); |
518 | | |
519 | 2 | pim_ifp->pim_sock_fd = -1; |
520 | 2 | pim_ifp->pim_sock_creation = 0; |
521 | 2 | pim_ifp->t_pim_sock_read = NULL; |
522 | | |
523 | 2 | pim_ifp->t_pim_hello_timer = NULL; |
524 | 2 | pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD; |
525 | 2 | pim_ifp->pim_default_holdtime = |
526 | 2 | -1; /* unset: means 3.5 * pim_hello_period */ |
527 | 2 | pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY; |
528 | 2 | pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY; |
529 | 2 | pim_ifp->pim_propagation_delay_msec = |
530 | 2 | PIM_DEFAULT_PROPAGATION_DELAY_MSEC; |
531 | 2 | pim_ifp->pim_override_interval_msec = |
532 | 2 | PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC; |
533 | 2 | pim_ifp->pim_can_disable_join_suppression = |
534 | 2 | PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION; |
535 | | |
536 | | /* neighbors without lan_delay */ |
537 | 2 | pim_ifp->pim_number_of_nonlandelay_neighbors = 0; |
538 | 2 | pim_ifp->pim_neighbors_highest_propagation_delay_msec = 0; |
539 | 2 | pim_ifp->pim_neighbors_highest_override_interval_msec = 0; |
540 | | |
541 | | /* DR Election */ |
542 | 2 | pim_ifp->pim_dr_election_last = 0; /* timestamp */ |
543 | 2 | pim_ifp->pim_dr_election_count = 0; |
544 | 2 | pim_ifp->pim_dr_election_changes = 0; |
545 | 2 | pim_ifp->pim_dr_num_nondrpri_neighbors = |
546 | 2 | 0; /* neighbors without dr_pri */ |
547 | 2 | pim_ifp->pim_dr_addr = pim_ifp->primary_address; |
548 | 2 | pim_ifp->am_i_dr = true; |
549 | | |
550 | 2 | pim_ifstat_reset(ifp); |
551 | 2 | } |
552 | | |
553 | | #if PIM_IPV == 4 |
554 | | static uint16_t ip_id = 0; |
555 | | #endif |
556 | | |
557 | | #if PIM_IPV == 4 |
558 | | static int pim_msg_send_frame(int fd, char *buf, size_t len, |
559 | | struct sockaddr *dst, size_t salen, |
560 | | const char *ifname) |
561 | 228 | { |
562 | 228 | if (sendto(fd, buf, len, MSG_DONTWAIT, dst, salen) >= 0) |
563 | 0 | return 0; |
564 | | |
565 | 228 | if (errno == EMSGSIZE) { |
566 | 0 | struct ip *ip = (struct ip *)buf; |
567 | 0 | size_t hdrsize = sizeof(struct ip); |
568 | 0 | size_t newlen1 = ((len - hdrsize) / 2) & 0xFFF8; |
569 | 0 | size_t sendlen = newlen1 + hdrsize; |
570 | 0 | size_t offset = ntohs(ip->ip_off); |
571 | 0 | int ret; |
572 | |
|
573 | 0 | ip->ip_len = htons(sendlen); |
574 | 0 | ip->ip_off = htons(offset | IP_MF); |
575 | |
|
576 | 0 | ret = pim_msg_send_frame(fd, buf, sendlen, dst, salen, ifname); |
577 | 0 | if (ret) |
578 | 0 | return ret; |
579 | | |
580 | 0 | struct ip *ip2 = (struct ip *)(buf + newlen1); |
581 | 0 | size_t newlen2 = len - sendlen; |
582 | |
|
583 | 0 | sendlen = newlen2 + hdrsize; |
584 | |
|
585 | 0 | memcpy(ip2, ip, hdrsize); |
586 | 0 | ip2->ip_len = htons(sendlen); |
587 | 0 | ip2->ip_off = htons(offset + (newlen1 >> 3)); |
588 | 0 | return pim_msg_send_frame(fd, (char *)ip2, sendlen, dst, salen, |
589 | 0 | ifname); |
590 | 0 | } |
591 | | |
592 | 228 | zlog_warn( |
593 | 228 | "%s: sendto() failure to %pSU: iface=%s fd=%d msg_size=%zd: %m", |
594 | 228 | __func__, dst, ifname, fd, len); |
595 | 228 | return -1; |
596 | 228 | } |
597 | | |
598 | | #else |
599 | | static int pim_msg_send_frame(pim_addr src, pim_addr dst, ifindex_t ifindex, |
600 | | struct iovec *message, int fd) |
601 | | { |
602 | | int retval; |
603 | | struct msghdr smsghdr = {}; |
604 | | struct cmsghdr *scmsgp; |
605 | | union cmsgbuf { |
606 | | struct cmsghdr hdr; |
607 | | uint8_t buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; |
608 | | }; |
609 | | struct in6_pktinfo *pktinfo; |
610 | | struct sockaddr_in6 dst_sin6 = {}; |
611 | | |
612 | | union cmsgbuf cmsg_buf = {}; |
613 | | |
614 | | /* destination address */ |
615 | | dst_sin6.sin6_family = AF_INET6; |
616 | | #ifdef SIN6_LEN |
617 | | dst_sin6.sin6_len = sizeof(struct sockaddr_in6); |
618 | | #endif /*SIN6_LEN*/ |
619 | | dst_sin6.sin6_addr = dst; |
620 | | dst_sin6.sin6_scope_id = ifindex; |
621 | | |
622 | | /* send msg hdr */ |
623 | | smsghdr.msg_iov = message; |
624 | | smsghdr.msg_iovlen = 1; |
625 | | smsghdr.msg_name = (caddr_t)&dst_sin6; |
626 | | smsghdr.msg_namelen = sizeof(dst_sin6); |
627 | | smsghdr.msg_control = (caddr_t)&cmsg_buf.buf; |
628 | | smsghdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); |
629 | | smsghdr.msg_flags = 0; |
630 | | |
631 | | scmsgp = CMSG_FIRSTHDR(&smsghdr); |
632 | | scmsgp->cmsg_level = IPPROTO_IPV6; |
633 | | scmsgp->cmsg_type = IPV6_PKTINFO; |
634 | | scmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); |
635 | | |
636 | | pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp)); |
637 | | pktinfo->ipi6_ifindex = ifindex; |
638 | | pktinfo->ipi6_addr = src; |
639 | | |
640 | | retval = sendmsg(fd, &smsghdr, 0); |
641 | | if (retval < 0) |
642 | | flog_err( |
643 | | EC_LIB_SOCKET, |
644 | | "sendmsg failed: source: %pI6 Dest: %pI6 ifindex: %d: %s (%d)", |
645 | | &src, &dst, ifindex, safe_strerror(errno), errno); |
646 | | |
647 | | return retval; |
648 | | } |
649 | | #endif |
650 | | |
651 | | int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, |
652 | | int pim_msg_size, struct interface *ifp) |
653 | 228 | { |
654 | 228 | struct pim_interface *pim_ifp; |
655 | | |
656 | | |
657 | 228 | pim_ifp = ifp->info; |
658 | | |
659 | 228 | if (pim_ifp->pim_passive_enable) { |
660 | 0 | if (PIM_DEBUG_PIM_PACKETS) |
661 | 0 | zlog_debug( |
662 | 0 | "skip sending PIM message on passive interface %s", |
663 | 0 | ifp->name); |
664 | 0 | return 0; |
665 | 0 | } |
666 | | |
667 | 228 | #if PIM_IPV == 4 |
668 | 228 | uint8_t ttl; |
669 | 228 | struct pim_msg_header *header; |
670 | 228 | unsigned char buffer[10000]; |
671 | | |
672 | 228 | memset(buffer, 0, 10000); |
673 | | |
674 | 228 | header = (struct pim_msg_header *)pim_msg; |
675 | | |
676 | | /* |
677 | | * Omnios apparently doesn't have a #define for IP default |
678 | | * ttl that is the same as all other platforms. |
679 | | */ |
680 | | #ifndef IPDEFTTL |
681 | | #define IPDEFTTL 64 |
682 | | #endif |
683 | | /* TTL for packets destine to ALL-PIM-ROUTERS is 1 */ |
684 | 228 | switch (header->type) { |
685 | 220 | case PIM_MSG_TYPE_HELLO: |
686 | 220 | case PIM_MSG_TYPE_JOIN_PRUNE: |
687 | 220 | case PIM_MSG_TYPE_BOOTSTRAP: |
688 | 220 | case PIM_MSG_TYPE_ASSERT: |
689 | 220 | ttl = 1; |
690 | 220 | break; |
691 | 0 | case PIM_MSG_TYPE_REGISTER: |
692 | 8 | case PIM_MSG_TYPE_REG_STOP: |
693 | 8 | case PIM_MSG_TYPE_GRAFT: |
694 | 8 | case PIM_MSG_TYPE_GRAFT_ACK: |
695 | 8 | case PIM_MSG_TYPE_CANDIDATE: |
696 | 8 | ttl = IPDEFTTL; |
697 | 8 | break; |
698 | 0 | default: |
699 | 0 | ttl = MAXTTL; |
700 | 0 | break; |
701 | 228 | } |
702 | | |
703 | 228 | struct ip *ip = (struct ip *)buffer; |
704 | 228 | struct sockaddr_in to = {}; |
705 | 228 | int sendlen = sizeof(*ip) + pim_msg_size; |
706 | 228 | socklen_t tolen; |
707 | 228 | unsigned char *msg_start; |
708 | | |
709 | 228 | ip->ip_id = htons(++ip_id); |
710 | 228 | ip->ip_hl = 5; |
711 | 228 | ip->ip_v = 4; |
712 | 228 | ip->ip_tos = IPTOS_PREC_INTERNETCONTROL; |
713 | 228 | ip->ip_p = PIM_IP_PROTO_PIM; |
714 | 228 | ip->ip_src = src; |
715 | 228 | ip->ip_dst = dst; |
716 | 228 | ip->ip_ttl = ttl; |
717 | 228 | ip->ip_len = htons(sendlen); |
718 | | |
719 | 228 | to.sin_family = AF_INET; |
720 | 228 | to.sin_addr = dst; |
721 | 228 | tolen = sizeof(to); |
722 | | |
723 | 228 | msg_start = buffer + sizeof(*ip); |
724 | 228 | memcpy(msg_start, pim_msg, pim_msg_size); |
725 | | |
726 | 228 | if (PIM_DEBUG_PIM_PACKETS) |
727 | 0 | zlog_debug("%s: to %pPA on %s: msg_size=%d checksum=%x", |
728 | 228 | __func__, &dst, ifp->name, pim_msg_size, |
729 | 228 | header->checksum); |
730 | | |
731 | 228 | if (PIM_DEBUG_PIM_PACKETDUMP_SEND) { |
732 | 0 | pim_pkt_dump(__func__, pim_msg, pim_msg_size); |
733 | 0 | } |
734 | | |
735 | 228 | pim_msg_send_frame(fd, (char *)buffer, sendlen, (struct sockaddr *)&to, |
736 | 228 | tolen, ifp->name); |
737 | 228 | return 0; |
738 | | |
739 | | #else |
740 | | struct iovec iovector[2]; |
741 | | |
742 | | iovector[0].iov_base = pim_msg; |
743 | | iovector[0].iov_len = pim_msg_size; |
744 | | |
745 | | pim_msg_send_frame(src, dst, ifp->ifindex, &iovector[0], fd); |
746 | | |
747 | | return 0; |
748 | | #endif |
749 | 228 | } |
750 | | |
751 | | static int hello_send(struct interface *ifp, uint16_t holdtime) |
752 | 220 | { |
753 | 220 | uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE]; |
754 | 220 | struct pim_interface *pim_ifp; |
755 | 220 | int pim_tlv_size; |
756 | 220 | int pim_msg_size; |
757 | | |
758 | 220 | pim_ifp = ifp->info; |
759 | | |
760 | 220 | if (PIM_DEBUG_PIM_HELLO) |
761 | 0 | zlog_debug( |
762 | 220 | "%s: to %pPA on %s: holdt=%u prop_d=%u overr_i=%u dis_join_supp=%d dr_prio=%u gen_id=%08x addrs=%d", |
763 | 220 | __func__, &qpim_all_pim_routers_addr, ifp->name, |
764 | 220 | holdtime, pim_ifp->pim_propagation_delay_msec, |
765 | 220 | pim_ifp->pim_override_interval_msec, |
766 | 220 | pim_ifp->pim_can_disable_join_suppression, |
767 | 220 | pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id, |
768 | 220 | listcount(ifp->connected)); |
769 | | |
770 | 220 | pim_tlv_size = pim_hello_build_tlv( |
771 | 220 | ifp, pim_msg + PIM_PIM_MIN_LEN, |
772 | 220 | sizeof(pim_msg) - PIM_PIM_MIN_LEN, holdtime, |
773 | 220 | pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id, |
774 | 220 | pim_ifp->pim_propagation_delay_msec, |
775 | 220 | pim_ifp->pim_override_interval_msec, |
776 | 220 | pim_ifp->pim_can_disable_join_suppression); |
777 | 220 | if (pim_tlv_size < 0) { |
778 | 0 | return -1; |
779 | 0 | } |
780 | | |
781 | 220 | pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN; |
782 | | |
783 | 220 | assert(pim_msg_size >= PIM_PIM_MIN_LEN); |
784 | 220 | assert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE); |
785 | | |
786 | 220 | pim_msg_build_header(pim_ifp->primary_address, |
787 | 220 | qpim_all_pim_routers_addr, pim_msg, pim_msg_size, |
788 | 220 | PIM_MSG_TYPE_HELLO, false); |
789 | | |
790 | 220 | if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address, |
791 | 220 | qpim_all_pim_routers_addr, pim_msg, pim_msg_size, |
792 | 220 | ifp)) { |
793 | 0 | if (PIM_DEBUG_PIM_HELLO) { |
794 | 0 | zlog_debug( |
795 | 0 | "%s: could not send PIM message on interface %s", |
796 | 0 | __func__, ifp->name); |
797 | 0 | } |
798 | 0 | return -2; |
799 | 0 | } |
800 | | |
801 | 220 | return 0; |
802 | 220 | } |
803 | | |
804 | | int pim_hello_send(struct interface *ifp, uint16_t holdtime) |
805 | 220 | { |
806 | 220 | struct pim_interface *pim_ifp = ifp->info; |
807 | | |
808 | 220 | if (if_is_loopback(ifp)) |
809 | 0 | return 0; |
810 | | |
811 | 220 | if (hello_send(ifp, holdtime)) { |
812 | 0 | ++pim_ifp->pim_ifstat_hello_sendfail; |
813 | |
|
814 | 0 | if (PIM_DEBUG_PIM_HELLO) { |
815 | 0 | zlog_warn("Could not send PIM hello on interface %s", |
816 | 0 | ifp->name); |
817 | 0 | } |
818 | 0 | return -1; |
819 | 0 | } |
820 | | |
821 | 220 | if (!pim_ifp->pim_passive_enable) { |
822 | 220 | ++pim_ifp->pim_ifstat_hello_sent; |
823 | 220 | PIM_IF_FLAG_SET_HELLO_SENT(pim_ifp->flags); |
824 | 220 | } |
825 | | |
826 | 220 | return 0; |
827 | 220 | } |
828 | | |
829 | | static void hello_resched(struct interface *ifp) |
830 | 220 | { |
831 | 220 | struct pim_interface *pim_ifp; |
832 | | |
833 | 220 | pim_ifp = ifp->info; |
834 | | |
835 | 220 | if (PIM_DEBUG_PIM_HELLO) { |
836 | 0 | zlog_debug("Rescheduling %d sec hello on interface %s", |
837 | 0 | pim_ifp->pim_hello_period, ifp->name); |
838 | 0 | } |
839 | 220 | EVENT_OFF(pim_ifp->t_pim_hello_timer); |
840 | 220 | event_add_timer(router->master, on_pim_hello_send, ifp, |
841 | 220 | pim_ifp->pim_hello_period, &pim_ifp->t_pim_hello_timer); |
842 | 220 | } |
843 | | |
844 | | /* |
845 | | Periodic hello timer |
846 | | */ |
847 | | static void on_pim_hello_send(struct event *t) |
848 | 0 | { |
849 | 0 | struct pim_interface *pim_ifp; |
850 | 0 | struct interface *ifp; |
851 | 0 |
|
852 | 0 | ifp = EVENT_ARG(t); |
853 | 0 | pim_ifp = ifp->info; |
854 | 0 |
|
855 | 0 | /* |
856 | 0 | * Schedule next hello |
857 | 0 | */ |
858 | 0 | hello_resched(ifp); |
859 | 0 |
|
860 | 0 | /* |
861 | 0 | * Send hello |
862 | 0 | */ |
863 | 0 | pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp)); |
864 | 0 | } |
865 | | |
866 | | /* |
867 | | RFC 4601: 4.3.1. Sending Hello Messages |
868 | | |
869 | | Thus, if a router needs to send a Join/Prune or Assert message on an |
870 | | interface on which it has not yet sent a Hello message with the |
871 | | currently configured IP address, then it MUST immediately send the |
872 | | relevant Hello message without waiting for the Hello Timer to |
873 | | expire, followed by the Join/Prune or Assert message. |
874 | | */ |
875 | | void pim_hello_restart_now(struct interface *ifp) |
876 | 220 | { |
877 | 220 | struct pim_interface *pim_ifp; |
878 | | |
879 | 220 | pim_ifp = ifp->info; |
880 | | |
881 | | /* |
882 | | * Reset next hello timer |
883 | | */ |
884 | 220 | hello_resched(ifp); |
885 | | |
886 | | /* |
887 | | * Immediately send hello |
888 | | */ |
889 | 220 | pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp)); |
890 | 220 | } |
891 | | |
892 | | /* |
893 | | RFC 4601: 4.3.1. Sending Hello Messages |
894 | | |
895 | | To allow new or rebooting routers to learn of PIM neighbors quickly, |
896 | | when a Hello message is received from a new neighbor, or a Hello |
897 | | message with a new GenID is received from an existing neighbor, a |
898 | | new Hello message should be sent on this interface after a |
899 | | randomized delay between 0 and Triggered_Hello_Delay. |
900 | | */ |
901 | | void pim_hello_restart_triggered(struct interface *ifp) |
902 | 196 | { |
903 | 196 | struct pim_interface *pim_ifp; |
904 | 196 | int triggered_hello_delay_msec; |
905 | 196 | int random_msec; |
906 | | |
907 | 196 | pim_ifp = ifp->info; |
908 | | |
909 | | /* |
910 | | * No need to ever start loopback or vrf device hello's |
911 | | */ |
912 | 196 | if (if_is_loopback(ifp)) |
913 | 0 | return; |
914 | | |
915 | | /* |
916 | | * There exists situations where we have the a RPF out this |
917 | | * interface, but we haven't formed a neighbor yet. This |
918 | | * happens especially during interface flaps. While |
919 | | * we would like to handle this more gracefully in other |
920 | | * parts of the code. In order to get us up and running |
921 | | * let's just send the hello immediate'ish |
922 | | * This should be revisited when we get nexthop tracking |
923 | | * in and when we have a better handle on safely |
924 | | * handling the rpf information for upstreams that |
925 | | * we cannot legally reach yet. |
926 | | */ |
927 | 196 | triggered_hello_delay_msec = 1; |
928 | | // triggered_hello_delay_msec = 1000 * |
929 | | // pim_ifp->pim_triggered_hello_delay; |
930 | | |
931 | 196 | if (pim_ifp->t_pim_hello_timer) { |
932 | 0 | long remain_msec = |
933 | 0 | pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer); |
934 | 0 | if (remain_msec <= triggered_hello_delay_msec) { |
935 | | /* Rescheduling hello would increase the delay, then |
936 | | it's faster |
937 | | to just wait for the scheduled periodic hello. */ |
938 | 0 | return; |
939 | 0 | } |
940 | | |
941 | 0 | EVENT_OFF(pim_ifp->t_pim_hello_timer); |
942 | 0 | } |
943 | | |
944 | 196 | random_msec = triggered_hello_delay_msec; |
945 | | // random_msec = random() % (triggered_hello_delay_msec + 1); |
946 | | |
947 | 196 | if (PIM_DEBUG_PIM_HELLO) { |
948 | 0 | zlog_debug("Scheduling %d msec triggered hello on interface %s", |
949 | 0 | random_msec, ifp->name); |
950 | 0 | } |
951 | | |
952 | 196 | event_add_timer_msec(router->master, on_pim_hello_send, ifp, |
953 | 196 | random_msec, &pim_ifp->t_pim_hello_timer); |
954 | 196 | } |
955 | | |
956 | | int pim_sock_add(struct interface *ifp) |
957 | 0 | { |
958 | 0 | struct pim_interface *pim_ifp; |
959 | 0 | uint32_t old_genid; |
960 | |
|
961 | 0 | pim_ifp = ifp->info; |
962 | 0 | assert(pim_ifp); |
963 | | |
964 | 0 | if (pim_ifp->pim_sock_fd >= 0) { |
965 | 0 | if (PIM_DEBUG_PIM_PACKETS) |
966 | 0 | zlog_debug( |
967 | 0 | "Can't recreate existing PIM socket fd=%d for interface %s", |
968 | 0 | pim_ifp->pim_sock_fd, ifp->name); |
969 | 0 | return -1; |
970 | 0 | } |
971 | | |
972 | 0 | pim_ifp->pim_sock_fd = pim_sock_open(ifp); |
973 | 0 | if (pim_ifp->pim_sock_fd < 0) { |
974 | 0 | if (PIM_DEBUG_PIM_PACKETS) |
975 | 0 | zlog_debug("Could not open PIM socket on interface %s", |
976 | 0 | ifp->name); |
977 | 0 | return -2; |
978 | 0 | } |
979 | | |
980 | 0 | pim_socket_ip_hdr(pim_ifp->pim_sock_fd); |
981 | |
|
982 | 0 | pim_ifp->t_pim_sock_read = NULL; |
983 | 0 | pim_ifp->pim_sock_creation = pim_time_monotonic_sec(); |
984 | | |
985 | | /* |
986 | | * Just ensure that the new generation id |
987 | | * actually chooses something different. |
988 | | * Actually ran across a case where this |
989 | | * happened, pre-switch to random(). |
990 | | * While this is unlikely to happen now |
991 | | * let's make sure it doesn't. |
992 | | */ |
993 | 0 | old_genid = pim_ifp->pim_generation_id; |
994 | |
|
995 | 0 | while (old_genid == pim_ifp->pim_generation_id) |
996 | 0 | pim_ifp->pim_generation_id = frr_weak_random(); |
997 | |
|
998 | 0 | zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d", ifp->name, |
999 | 0 | ifp->ifindex); |
1000 | | |
1001 | | /* |
1002 | | * Start receiving PIM messages |
1003 | | */ |
1004 | 0 | pim_sock_read_on(ifp); |
1005 | | |
1006 | | /* |
1007 | | * Start sending PIM hello's |
1008 | | */ |
1009 | 0 | pim_hello_restart_triggered(ifp); |
1010 | |
|
1011 | 0 | return 0; |
1012 | 0 | } |