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