]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_igmp.c
Merge branch 'frr/pull/536'
[mirror_frr.git] / pimd / pim_igmp.c
1 /*
2 * PIM for Quagga
3 * Copyright (C) 2008 Everton da Silva Marques
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include <zebra.h>
21
22 #include "memory.h"
23 #include "prefix.h"
24 #include "if.h"
25 #include "hash.h"
26 #include "jhash.h"
27
28 #include "pimd.h"
29 #include "pim_igmp.h"
30 #include "pim_igmpv2.h"
31 #include "pim_igmpv3.h"
32 #include "pim_iface.h"
33 #include "pim_sock.h"
34 #include "pim_mroute.h"
35 #include "pim_str.h"
36 #include "pim_util.h"
37 #include "pim_time.h"
38 #include "pim_zebra.h"
39
40 static void group_timer_off(struct igmp_group *group);
41
42 /* This socket is used for TXing IGMP packets only, IGMP RX happens
43 * in pim_mroute_msg()
44 */
45 static int igmp_sock_open(struct in_addr ifaddr, struct interface *ifp, uint32_t pim_options)
46 {
47 int fd;
48 int join = 0;
49 struct in_addr group;
50
51 fd = pim_socket_mcast(IPPROTO_IGMP, ifaddr, ifp, 1);
52
53 if (fd < 0)
54 return -1;
55
56 if (PIM_IF_TEST_IGMP_LISTEN_ALLROUTERS(pim_options)) {
57 if (inet_aton(PIM_ALL_ROUTERS, &group)) {
58 if (!pim_socket_join(fd, group, ifaddr, ifp->ifindex))
59 ++join;
60 }
61 else {
62 zlog_warn("%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s",
63 __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr),
64 PIM_ALL_ROUTERS, errno, safe_strerror(errno));
65 }
66 }
67
68 /*
69 IGMP routers periodically send IGMP general queries to AllSystems=224.0.0.1
70 IGMP routers must receive general queries for querier election.
71 */
72 if (inet_aton(PIM_ALL_SYSTEMS, &group)) {
73 if (!pim_socket_join(fd, group, ifaddr, ifp->ifindex))
74 ++join;
75 }
76 else {
77 zlog_warn("%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s",
78 __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr),
79 PIM_ALL_SYSTEMS, errno, safe_strerror(errno));
80 }
81
82 if (inet_aton(PIM_ALL_IGMP_ROUTERS, &group)) {
83 if (!pim_socket_join(fd, group, ifaddr, ifp->ifindex)) {
84 ++join;
85 }
86 }
87 else {
88 zlog_warn("%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s",
89 __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr),
90 PIM_ALL_IGMP_ROUTERS, errno, safe_strerror(errno));
91 }
92
93 if (!join) {
94 zlog_err("IGMP socket fd=%d could not join any group on interface address %s",
95 fd, inet_ntoa(ifaddr));
96 close(fd);
97 fd = -1;
98 }
99
100 return fd;
101 }
102
103 #undef IGMP_SOCK_DUMP
104
105 #ifdef IGMP_SOCK_DUMP
106 static void igmp_sock_dump(array_t *igmp_sock_array)
107 {
108 int size = array_size(igmp_sock_array);
109 for (int i = 0; i < size; ++i) {
110
111 struct igmp_sock *igmp = array_get(igmp_sock_array, i);
112
113 zlog_debug("%s %s: [%d/%d] igmp_addr=%s fd=%d",
114 __FILE__, __PRETTY_FUNCTION__,
115 i, size,
116 inet_ntoa(igmp->ifaddr),
117 igmp->fd);
118 }
119 }
120 #endif
121
122 struct igmp_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list,
123 struct in_addr ifaddr)
124 {
125 struct listnode *sock_node;
126 struct igmp_sock *igmp;
127
128 #ifdef IGMP_SOCK_DUMP
129 igmp_sock_dump(igmp_sock_list);
130 #endif
131
132 for (ALL_LIST_ELEMENTS_RO(igmp_sock_list, sock_node, igmp))
133 if (ifaddr.s_addr == igmp->ifaddr.s_addr)
134 return igmp;
135
136 return 0;
137 }
138
139 struct igmp_sock *igmp_sock_lookup_by_fd(struct list *igmp_sock_list,
140 int fd)
141 {
142 struct listnode *sock_node;
143 struct igmp_sock *igmp;
144
145 for (ALL_LIST_ELEMENTS_RO(igmp_sock_list, sock_node, igmp))
146 if (fd == igmp->fd)
147 return igmp;
148
149 return 0;
150 }
151
152 static int pim_igmp_other_querier_expire(struct thread *t)
153 {
154 struct igmp_sock *igmp;
155
156 igmp = THREAD_ARG(t);
157
158 zassert(igmp->t_other_querier_timer);
159 zassert(!igmp->t_igmp_query_timer);
160
161 if (PIM_DEBUG_IGMP_TRACE) {
162 char ifaddr_str[INET_ADDRSTRLEN];
163 pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
164 zlog_debug("%s: Querier %s resuming",
165 __PRETTY_FUNCTION__,
166 ifaddr_str);
167 }
168
169 igmp->t_other_querier_timer = NULL;
170
171 /*
172 We are the current querier, then
173 re-start sending general queries.
174 */
175 pim_igmp_general_query_on(igmp);
176
177 return 0;
178 }
179
180 void pim_igmp_other_querier_timer_on(struct igmp_sock *igmp)
181 {
182 long other_querier_present_interval_msec;
183 struct pim_interface *pim_ifp;
184
185 zassert(igmp);
186 zassert(igmp->interface);
187 zassert(igmp->interface->info);
188
189 pim_ifp = igmp->interface->info;
190
191 if (igmp->t_other_querier_timer) {
192 /*
193 There is other querier present already,
194 then reset the other-querier-present timer.
195 */
196
197 if (PIM_DEBUG_IGMP_TRACE) {
198 char ifaddr_str[INET_ADDRSTRLEN];
199 pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
200 zlog_debug("Querier %s resetting TIMER event for Other-Querier-Present",
201 ifaddr_str);
202 }
203
204 THREAD_OFF(igmp->t_other_querier_timer);
205 zassert(!igmp->t_other_querier_timer);
206 }
207 else {
208 /*
209 We are the current querier, then stop sending general queries:
210 igmp->t_igmp_query_timer = NULL;
211 */
212 pim_igmp_general_query_off(igmp);
213 }
214
215 /*
216 Since this socket is starting the other-querier-present timer,
217 there should not be periodic query timer for this socket.
218 */
219 zassert(!igmp->t_igmp_query_timer);
220
221 /*
222 RFC 3376: 8.5. Other Querier Present Interval
223
224 The Other Querier Present Interval is the length of time that must
225 pass before a multicast router decides that there is no longer
226 another multicast router which should be the querier. This value
227 MUST be ((the Robustness Variable) times (the Query Interval)) plus
228 (one half of one Query Response Interval).
229
230 other_querier_present_interval_msec = \
231 igmp->querier_robustness_variable * \
232 1000 * igmp->querier_query_interval + \
233 100 * (pim_ifp->query_max_response_time_dsec >> 1);
234 */
235 other_querier_present_interval_msec =
236 PIM_IGMP_OQPI_MSEC(igmp->querier_robustness_variable,
237 igmp->querier_query_interval,
238 pim_ifp->igmp_query_max_response_time_dsec);
239
240 if (PIM_DEBUG_IGMP_TRACE) {
241 char ifaddr_str[INET_ADDRSTRLEN];
242 pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
243 zlog_debug("Querier %s scheduling %ld.%03ld sec TIMER event for Other-Querier-Present",
244 ifaddr_str,
245 other_querier_present_interval_msec / 1000,
246 other_querier_present_interval_msec % 1000);
247 }
248
249 thread_add_timer_msec(master, pim_igmp_other_querier_expire, igmp,
250 other_querier_present_interval_msec,
251 &igmp->t_other_querier_timer);
252 }
253
254 void pim_igmp_other_querier_timer_off(struct igmp_sock *igmp)
255 {
256 zassert(igmp);
257
258 if (PIM_DEBUG_IGMP_TRACE) {
259 if (igmp->t_other_querier_timer) {
260 char ifaddr_str[INET_ADDRSTRLEN];
261 pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
262 zlog_debug("IGMP querier %s fd=%d cancelling other-querier-present TIMER event on %s",
263 ifaddr_str, igmp->fd, igmp->interface->name);
264 }
265 }
266 THREAD_OFF(igmp->t_other_querier_timer);
267 zassert(!igmp->t_other_querier_timer);
268 }
269
270 static int
271 igmp_recv_query(struct igmp_sock *igmp, int query_version,
272 int max_resp_code,
273 struct in_addr from, const char *from_str,
274 char *igmp_msg, int igmp_msg_len)
275 {
276 struct interface *ifp;
277 struct pim_interface *pim_ifp;
278 struct in_addr group_addr;
279 uint16_t recv_checksum;
280 uint16_t checksum;
281
282 memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
283
284 ifp = igmp->interface;
285 pim_ifp = ifp->info;
286
287 recv_checksum = *(uint16_t *) (igmp_msg + IGMP_CHECKSUM_OFFSET);
288
289 /* for computing checksum */
290 *(uint16_t *) (igmp_msg + IGMP_CHECKSUM_OFFSET) = 0;
291
292 checksum = in_cksum(igmp_msg, igmp_msg_len);
293 if (checksum != recv_checksum) {
294 zlog_warn("Recv IGMP query v%d from %s on %s: checksum mismatch: received=%x computed=%x",
295 query_version, from_str, ifp->name, recv_checksum, checksum);
296 return -1;
297 }
298
299 /* RFC 3376 defines some guidelines on operating in backwards compatibility
300 * with older versions of IGMP but there are some gaps in the logic:
301 *
302 * - once we drop from say version 3 to version 2 we will never go back to
303 * version 3 even if the node that TXed an IGMP v2 query upgrades to v3
304 *
305 * - The node with the lowest IP is the querier so we will only know to drop
306 * from v3 to v2 if the node that is the querier is also the one that is
307 * running igmp v2. If a non-querier only supports igmp v2 we will have
308 * no way of knowing.
309 *
310 * For now we will simplify things and inform the user that they need to
311 * configure all PIM routers to use the same version of IGMP.
312 */
313 if (query_version != pim_ifp->igmp_version) {
314 zlog_warn("Recv IGMP query v%d from %s on %s but we are using v%d, please "
315 "configure all PIM routers on this subnet to use the same "
316 "IGMP version",
317 query_version, from_str, ifp->name, pim_ifp->igmp_version);
318 return 0;
319 }
320
321 if (PIM_DEBUG_IGMP_PACKETS) {
322 char group_str[INET_ADDRSTRLEN];
323 pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
324 zlog_debug("Recv IGMP query v%d from %s on %s for group %s",
325 query_version, from_str, ifp->name, group_str);
326 }
327
328 /*
329 RFC 3376: 6.6.2. Querier Election
330
331 When a router receives a query with a lower IP address, it sets
332 the Other-Querier-Present timer to Other Querier Present Interval
333 and ceases to send queries on the network if it was the previously
334 elected querier.
335 */
336 if (ntohl(from.s_addr) < ntohl(igmp->ifaddr.s_addr)) {
337
338 if (PIM_DEBUG_IGMP_TRACE) {
339 char ifaddr_str[INET_ADDRSTRLEN];
340 pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
341 zlog_debug("%s: local address %s (%u) lost querier election to %s (%u)",
342 ifp->name,
343 ifaddr_str, ntohl(igmp->ifaddr.s_addr),
344 from_str, ntohl(from.s_addr));
345 }
346
347 pim_igmp_other_querier_timer_on(igmp);
348 }
349
350 /* IGMP version 3 is the only one where we process the RXed query */
351 if (query_version == 3) {
352 igmp_v3_recv_query(igmp, from_str, igmp_msg);
353 }
354
355 return 0;
356 }
357
358 static void on_trace(const char *label,
359 struct interface *ifp, struct in_addr from)
360 {
361 if (PIM_DEBUG_IGMP_TRACE) {
362 char from_str[INET_ADDRSTRLEN];
363 pim_inet4_dump("<from?>", from, from_str, sizeof(from_str));
364 zlog_debug("%s: from %s on %s",
365 label, from_str, ifp->name);
366 }
367 }
368
369 static int
370 igmp_v1_recv_report (struct igmp_sock *igmp,
371 struct in_addr from, const char *from_str,
372 char *igmp_msg, int igmp_msg_len)
373 {
374 struct interface *ifp = igmp->interface;
375 struct igmp_group *group;
376 struct in_addr group_addr;
377
378 on_trace(__PRETTY_FUNCTION__, igmp->interface, from);
379
380 if (igmp_msg_len != IGMP_V12_MSG_SIZE) {
381 zlog_warn("Recv IGMP report v1 from %s on %s: size=%d other than correct=%d",
382 from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE);
383 return -1;
384 }
385
386 if (PIM_DEBUG_IGMP_TRACE) {
387 zlog_warn("%s %s: FIXME WRITEME",
388 __FILE__, __PRETTY_FUNCTION__);
389 }
390
391 memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
392
393 /* non-existant group is created as INCLUDE {empty} */
394 group = igmp_add_group_by_addr(igmp, group_addr);
395 if (!group) {
396 return -1;
397 }
398
399 group->last_igmp_v1_report_dsec = pim_time_monotonic_dsec();
400
401 return 0;
402 }
403
404 int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len)
405 {
406 struct ip *ip_hdr;
407 size_t ip_hlen; /* ip header length in bytes */
408 char *igmp_msg;
409 int igmp_msg_len;
410 int msg_type;
411 char from_str[INET_ADDRSTRLEN];
412 char to_str[INET_ADDRSTRLEN];
413
414 if (len < sizeof(*ip_hdr)) {
415 zlog_warn("IGMP packet size=%zu shorter than minimum=%zu",
416 len, sizeof(*ip_hdr));
417 return -1;
418 }
419
420 ip_hdr = (struct ip *) buf;
421
422 pim_inet4_dump("<src?>", ip_hdr->ip_src, from_str , sizeof(from_str));
423 pim_inet4_dump("<dst?>", ip_hdr->ip_dst, to_str , sizeof(to_str));
424
425 ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */
426
427 if (PIM_DEBUG_IGMP_PACKETS) {
428 zlog_debug("Recv IP packet from %s to %s on %s: size=%zu ip_header_size=%zu ip_proto=%d",
429 from_str, to_str, igmp->interface->name, len, ip_hlen, ip_hdr->ip_p);
430 }
431
432 igmp_msg = buf + ip_hlen;
433 msg_type = *igmp_msg;
434 igmp_msg_len = len - ip_hlen;
435
436 if (PIM_DEBUG_IGMP_PACKETS) {
437 zlog_debug("Recv IGMP packet from %s to %s on %s: ttl=%d msg_type=%d msg_size=%d",
438 from_str, to_str, igmp->interface->name, ip_hdr->ip_ttl, msg_type,
439 igmp_msg_len);
440 }
441
442 if (igmp_msg_len < PIM_IGMP_MIN_LEN) {
443 zlog_warn("IGMP message size=%d shorter than minimum=%d",
444 igmp_msg_len, PIM_IGMP_MIN_LEN);
445 return -1;
446 }
447
448 switch (msg_type) {
449 case PIM_IGMP_MEMBERSHIP_QUERY:
450 {
451 int max_resp_code = igmp_msg[1];
452 int query_version;
453
454 /*
455 RFC 3376: 7.1. Query Version Distinctions
456 IGMPv1 Query: length = 8 octets AND Max Resp Code field is zero
457 IGMPv2 Query: length = 8 octets AND Max Resp Code field is non-zero
458 IGMPv3 Query: length >= 12 octets
459 */
460
461 if (igmp_msg_len == 8) {
462 query_version = max_resp_code ? 2 : 1;
463 }
464 else if (igmp_msg_len >= 12) {
465 query_version = 3;
466 }
467 else {
468 zlog_warn("Unknown IGMP query version");
469 return -1;
470 }
471
472 return igmp_recv_query(igmp, query_version, max_resp_code,
473 ip_hdr->ip_src, from_str,
474 igmp_msg, igmp_msg_len);
475 }
476
477 case PIM_IGMP_V3_MEMBERSHIP_REPORT:
478 return igmp_v3_recv_report(igmp, ip_hdr->ip_src, from_str,
479 igmp_msg, igmp_msg_len);
480
481 case PIM_IGMP_V2_MEMBERSHIP_REPORT:
482 return igmp_v2_recv_report(igmp, ip_hdr->ip_src, from_str,
483 igmp_msg, igmp_msg_len);
484
485 case PIM_IGMP_V1_MEMBERSHIP_REPORT:
486 return igmp_v1_recv_report(igmp, ip_hdr->ip_src, from_str,
487 igmp_msg, igmp_msg_len);
488
489 case PIM_IGMP_V2_LEAVE_GROUP:
490 return igmp_v2_recv_leave(igmp, ip_hdr->ip_src, from_str,
491 igmp_msg, igmp_msg_len);
492 }
493
494 zlog_warn("Ignoring unsupported IGMP message type: %d", msg_type);
495
496 return -1;
497 }
498
499 static int pim_igmp_general_query(struct thread *t);
500
501 void pim_igmp_general_query_on(struct igmp_sock *igmp)
502 {
503 struct pim_interface *pim_ifp;
504 int startup_mode;
505 int query_interval;
506
507 /*
508 Since this socket is starting as querier,
509 there should not exist a timer for other-querier-present.
510 */
511 zassert(!igmp->t_other_querier_timer);
512 pim_ifp = igmp->interface->info;
513 zassert(pim_ifp);
514
515 /*
516 RFC 3376: 8.6. Startup Query Interval
517
518 The Startup Query Interval is the interval between General Queries
519 sent by a Querier on startup. Default: 1/4 the Query Interval.
520 The first one should be sent out immediately instead of 125/4
521 seconds from now.
522 */
523 startup_mode = igmp->startup_query_count > 0;
524 if (startup_mode) {
525 /*
526 * If this is the first time we are sending a query on a
527 * newly configured igmp interface send it out in 1 second
528 * just to give the entire world a tiny bit of time to settle
529 * else the query interval is:
530 * query_interval = pim_ifp->igmp_default_query_interval >> 2;
531 */
532 if (igmp->startup_query_count == igmp->querier_robustness_variable)
533 query_interval = 1;
534 else
535 query_interval = PIM_IGMP_SQI(pim_ifp->igmp_default_query_interval);
536
537 --igmp->startup_query_count;
538 }
539 else {
540 query_interval = igmp->querier_query_interval;
541 }
542
543 if (PIM_DEBUG_IGMP_TRACE) {
544 char ifaddr_str[INET_ADDRSTRLEN];
545 pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
546 zlog_debug("Querier %s scheduling %d-second (%s) TIMER event for IGMP query on fd=%d",
547 ifaddr_str,
548 query_interval,
549 startup_mode ? "startup" : "non-startup",
550 igmp->fd);
551 }
552 igmp->t_igmp_query_timer = NULL;
553 thread_add_timer(master, pim_igmp_general_query, igmp, query_interval,
554 &igmp->t_igmp_query_timer);
555 }
556
557 void pim_igmp_general_query_off(struct igmp_sock *igmp)
558 {
559 zassert(igmp);
560
561 if (PIM_DEBUG_IGMP_TRACE) {
562 if (igmp->t_igmp_query_timer) {
563 char ifaddr_str[INET_ADDRSTRLEN];
564 pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
565 zlog_debug("IGMP querier %s fd=%d cancelling query TIMER event on %s",
566 ifaddr_str, igmp->fd, igmp->interface->name);
567 }
568 }
569 THREAD_OFF(igmp->t_igmp_query_timer);
570 }
571
572 /* Issue IGMP general query */
573 static int pim_igmp_general_query(struct thread *t)
574 {
575 struct igmp_sock *igmp;
576 struct in_addr dst_addr;
577 struct in_addr group_addr;
578 struct pim_interface *pim_ifp;
579 int query_buf_size;
580
581 igmp = THREAD_ARG(t);
582
583 zassert(igmp->interface);
584 zassert(igmp->interface->info);
585
586 pim_ifp = igmp->interface->info;
587
588 if (pim_ifp->igmp_version == 3) {
589 query_buf_size = PIM_IGMP_BUFSIZE_WRITE;
590 } else {
591 query_buf_size = IGMP_V12_MSG_SIZE;
592 }
593
594 char query_buf[query_buf_size];
595
596 /*
597 RFC3376: 4.1.12. IP Destination Addresses for Queries
598
599 In IGMPv3, General Queries are sent with an IP destination address
600 of 224.0.0.1, the all-systems multicast address. Group-Specific
601 and Group-and-Source-Specific Queries are sent with an IP
602 destination address equal to the multicast address of interest.
603 */
604
605 dst_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
606 group_addr.s_addr = PIM_NET_INADDR_ANY;
607
608 if (PIM_DEBUG_IGMP_TRACE) {
609 char querier_str[INET_ADDRSTRLEN];
610 char dst_str[INET_ADDRSTRLEN];
611 pim_inet4_dump("<querier?>", igmp->ifaddr, querier_str,
612 sizeof(querier_str));
613 pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
614 zlog_debug("Querier %s issuing IGMP general query to %s on %s",
615 querier_str, dst_str, igmp->interface->name);
616 }
617
618 igmp_send_query (pim_ifp->igmp_version,
619 0 /* igmp_group */,
620 igmp->fd,
621 igmp->interface->name,
622 query_buf,
623 sizeof(query_buf),
624 0 /* num_sources */,
625 dst_addr,
626 group_addr,
627 pim_ifp->igmp_query_max_response_time_dsec,
628 1 /* s_flag: always set for general queries */,
629 igmp->querier_robustness_variable,
630 igmp->querier_query_interval);
631
632 pim_igmp_general_query_on(igmp);
633
634 return 0;
635 }
636
637 static void sock_close(struct igmp_sock *igmp)
638 {
639 pim_igmp_other_querier_timer_off(igmp);
640 pim_igmp_general_query_off(igmp);
641
642 if (PIM_DEBUG_IGMP_TRACE_DETAIL) {
643 if (igmp->t_igmp_read) {
644 zlog_debug("Cancelling READ event on IGMP socket %s fd=%d on interface %s",
645 inet_ntoa(igmp->ifaddr), igmp->fd,
646 igmp->interface->name);
647 }
648 }
649 THREAD_OFF(igmp->t_igmp_read);
650
651 if (close(igmp->fd)) {
652 zlog_err("Failure closing IGMP socket %s fd=%d on interface %s: errno=%d: %s",
653 inet_ntoa(igmp->ifaddr), igmp->fd, igmp->interface->name,
654 errno, safe_strerror(errno));
655 }
656
657 if (PIM_DEBUG_IGMP_TRACE_DETAIL) {
658 zlog_debug("Deleted IGMP socket %s fd=%d on interface %s",
659 inet_ntoa(igmp->ifaddr), igmp->fd, igmp->interface->name);
660 }
661 }
662
663 void igmp_startup_mode_on(struct igmp_sock *igmp)
664 {
665 struct pim_interface *pim_ifp;
666
667 pim_ifp = igmp->interface->info;
668
669 /*
670 RFC 3376: 8.7. Startup Query Count
671
672 The Startup Query Count is the number of Queries sent out on
673 startup, separated by the Startup Query Interval. Default: the
674 Robustness Variable.
675 */
676 igmp->startup_query_count = igmp->querier_robustness_variable;
677
678 /*
679 Since we're (re)starting, reset QQI to default Query Interval
680 */
681 igmp->querier_query_interval = pim_ifp->igmp_default_query_interval;
682 }
683
684 static void igmp_group_free(struct igmp_group *group)
685 {
686 list_free(group->group_source_list);
687
688 XFREE(MTYPE_PIM_IGMP_GROUP, group);
689 }
690
691 static void igmp_group_delete(struct igmp_group *group)
692 {
693 struct listnode *src_node;
694 struct listnode *src_nextnode;
695 struct igmp_source *src;
696
697 if (PIM_DEBUG_IGMP_TRACE) {
698 char group_str[INET_ADDRSTRLEN];
699 pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
700 zlog_debug("Deleting IGMP group %s from socket %d interface %s",
701 group_str,
702 group->group_igmp_sock->fd,
703 group->group_igmp_sock->interface->name);
704 }
705
706 for (ALL_LIST_ELEMENTS(group->group_source_list, src_node, src_nextnode, src)) {
707 igmp_source_delete(src);
708 }
709
710 if (group->t_group_query_retransmit_timer) {
711 THREAD_OFF(group->t_group_query_retransmit_timer);
712 }
713
714 group_timer_off(group);
715 listnode_delete(group->group_igmp_sock->igmp_group_list, group);
716 hash_release (group->group_igmp_sock->igmp_group_hash, group);
717
718 igmp_group_free(group);
719 }
720
721 void igmp_group_delete_empty_include(struct igmp_group *group)
722 {
723 zassert(!group->group_filtermode_isexcl);
724 zassert(!listcount(group->group_source_list));
725
726 igmp_group_delete(group);
727 }
728
729 void igmp_sock_free(struct igmp_sock *igmp)
730 {
731 zassert(!igmp->t_igmp_read);
732 zassert(!igmp->t_igmp_query_timer);
733 zassert(!igmp->t_other_querier_timer);
734 zassert(igmp->igmp_group_list);
735 zassert(!listcount(igmp->igmp_group_list));
736
737 list_free(igmp->igmp_group_list);
738 hash_free(igmp->igmp_group_hash);
739
740 XFREE(MTYPE_PIM_IGMP_SOCKET, igmp);
741 }
742
743 void igmp_sock_delete(struct igmp_sock *igmp)
744 {
745 struct pim_interface *pim_ifp;
746 struct listnode *grp_node;
747 struct listnode *grp_nextnode;
748 struct igmp_group *grp;
749
750 for (ALL_LIST_ELEMENTS(igmp->igmp_group_list, grp_node, grp_nextnode, grp)) {
751 igmp_group_delete(grp);
752 }
753
754 sock_close(igmp);
755
756 pim_ifp = igmp->interface->info;
757
758 listnode_delete(pim_ifp->igmp_socket_list, igmp);
759
760 igmp_sock_free(igmp);
761 }
762
763 void
764 igmp_sock_delete_all (struct interface *ifp)
765 {
766 struct pim_interface *pim_ifp;
767 struct listnode *igmp_node, *igmp_nextnode;
768 struct igmp_sock *igmp;
769
770 pim_ifp = ifp->info;
771
772 for (ALL_LIST_ELEMENTS (pim_ifp->igmp_socket_list, igmp_node,
773 igmp_nextnode, igmp))
774 {
775 igmp_sock_delete(igmp);
776 }
777 }
778
779 static unsigned int
780 igmp_group_hash_key (void *arg)
781 {
782 struct igmp_group *group = (struct igmp_group *)arg;
783
784 return jhash_1word(group->group_addr.s_addr, 0);
785 }
786
787 static int
788 igmp_group_hash_equal (const void *arg1, const void *arg2)
789 {
790 const struct igmp_group *g1 = (const struct igmp_group *)arg1;
791 const struct igmp_group *g2 = (const struct igmp_group *)arg2;
792
793 if (g1->group_addr.s_addr == g2->group_addr.s_addr)
794 return 1;
795
796 return 0;
797 }
798
799 static struct igmp_sock *igmp_sock_new(int fd,
800 struct in_addr ifaddr,
801 struct interface *ifp)
802 {
803 struct pim_interface *pim_ifp;
804 struct igmp_sock *igmp;
805
806 pim_ifp = ifp->info;
807
808 if (PIM_DEBUG_IGMP_TRACE) {
809 zlog_debug("Creating IGMP socket fd=%d for address %s on interface %s",
810 fd, inet_ntoa(ifaddr), ifp->name);
811 }
812
813 igmp = XCALLOC(MTYPE_PIM_IGMP_SOCKET, sizeof(*igmp));
814 if (!igmp) {
815 zlog_warn("%s %s: XCALLOC() failure",
816 __FILE__, __PRETTY_FUNCTION__);
817 return 0;
818 }
819
820 igmp->igmp_group_list = list_new();
821 if (!igmp->igmp_group_list) {
822 zlog_err("%s %s: failure: igmp_group_list = list_new()",
823 __FILE__, __PRETTY_FUNCTION__);
824 return 0;
825 }
826 igmp->igmp_group_list->del = (void (*)(void *)) igmp_group_free;
827
828 igmp->igmp_group_hash = hash_create (igmp_group_hash_key,
829 igmp_group_hash_equal);
830
831 igmp->fd = fd;
832 igmp->interface = ifp;
833 igmp->ifaddr = ifaddr;
834 igmp->t_igmp_read = NULL;
835 igmp->t_igmp_query_timer = NULL;
836 igmp->t_other_querier_timer = NULL; /* no other querier present */
837 igmp->querier_robustness_variable = pim_ifp->igmp_default_robustness_variable;
838 igmp->sock_creation = pim_time_monotonic_sec();
839
840 /*
841 igmp_startup_mode_on() will reset QQI:
842
843 igmp->querier_query_interval = pim_ifp->igmp_default_query_interval;
844 */
845 igmp_startup_mode_on(igmp);
846 pim_igmp_general_query_on(igmp);
847
848 return igmp;
849 }
850
851 static void igmp_read_on (struct igmp_sock *igmp);
852
853 static int
854 pim_igmp_read (struct thread *t)
855 {
856 uint8_t buf[10000];
857 struct igmp_sock *igmp = (struct igmp_sock *)THREAD_ARG(t);
858 struct sockaddr_in from;
859 struct sockaddr_in to;
860 socklen_t fromlen = sizeof(from);
861 socklen_t tolen = sizeof(to);
862 ifindex_t ifindex = -1;
863 int cont = 1;
864 int len;
865
866 while (cont)
867 {
868 len = pim_socket_recvfromto(igmp->fd, buf, sizeof(buf),
869 &from, &fromlen,
870 &to, &tolen,
871 &ifindex);
872 if (len < 0)
873 {
874 if (errno == EINTR)
875 continue;
876 if (errno == EWOULDBLOCK || errno == EAGAIN)
877 break;
878
879 goto done;
880 }
881 }
882
883 done:
884 igmp_read_on(igmp);
885 return 0;
886 }
887
888 static void
889 igmp_read_on (struct igmp_sock *igmp)
890 {
891
892 if (PIM_DEBUG_IGMP_TRACE_DETAIL) {
893 zlog_debug("Scheduling READ event on IGMP socket fd=%d",
894 igmp->fd);
895 }
896 igmp->t_igmp_read = NULL;
897 thread_add_read(master, pim_igmp_read, igmp, igmp->fd, &igmp->t_igmp_read);
898
899 }
900
901 struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list,
902 struct in_addr ifaddr,
903 struct interface *ifp)
904 {
905 struct pim_interface *pim_ifp;
906 struct igmp_sock *igmp;
907 int fd;
908
909 pim_ifp = ifp->info;
910
911 fd = igmp_sock_open(ifaddr, ifp, pim_ifp->options);
912 if (fd < 0) {
913 zlog_warn("Could not open IGMP socket for %s on %s",
914 inet_ntoa(ifaddr), ifp->name);
915 return 0;
916 }
917
918 igmp = igmp_sock_new(fd, ifaddr, ifp);
919 if (!igmp) {
920 zlog_err("%s %s: igmp_sock_new() failure",
921 __FILE__, __PRETTY_FUNCTION__);
922 close(fd);
923 return 0;
924 }
925
926 igmp_read_on (igmp);
927
928 listnode_add(igmp_sock_list, igmp);
929
930 #ifdef IGMP_SOCK_DUMP
931 igmp_sock_dump(igmp_sock_array);
932 #endif
933
934 return igmp;
935 }
936
937 /*
938 RFC 3376: 6.5. Switching Router Filter-Modes
939
940 When a router's filter-mode for a group is EXCLUDE and the group
941 timer expires, the router filter-mode for the group transitions to
942 INCLUDE.
943
944 A router uses source records with running source timers as its state
945 for the switch to a filter-mode of INCLUDE. If there are any source
946 records with source timers greater than zero (i.e., requested to be
947 forwarded), a router switches to filter-mode of INCLUDE using those
948 source records. Source records whose timers are zero (from the
949 previous EXCLUDE mode) are deleted.
950 */
951 static int igmp_group_timer(struct thread *t)
952 {
953 struct igmp_group *group;
954
955 group = THREAD_ARG(t);
956
957 if (PIM_DEBUG_IGMP_TRACE) {
958 char group_str[INET_ADDRSTRLEN];
959 pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
960 zlog_debug("%s: Timer for group %s on interface %s",
961 __PRETTY_FUNCTION__,
962 group_str, group->group_igmp_sock->interface->name);
963 }
964
965 zassert(group->group_filtermode_isexcl);
966
967 group->t_group_timer = NULL;
968 group->group_filtermode_isexcl = 0;
969
970 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
971 igmp_anysource_forward_stop(group);
972
973 igmp_source_delete_expired(group->group_source_list);
974
975 zassert(!group->t_group_timer);
976 zassert(!group->group_filtermode_isexcl);
977
978 /*
979 RFC 3376: 6.2.2. Definition of Group Timers
980
981 If there are no more source records for the group, delete group
982 record.
983 */
984 if (listcount(group->group_source_list) < 1) {
985 igmp_group_delete_empty_include(group);
986 }
987
988 return 0;
989 }
990
991 static void group_timer_off(struct igmp_group *group)
992 {
993 if (!group->t_group_timer)
994 return;
995
996 if (PIM_DEBUG_IGMP_TRACE) {
997 char group_str[INET_ADDRSTRLEN];
998 pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
999 zlog_debug("Cancelling TIMER event for group %s on %s",
1000 group_str, group->group_igmp_sock->interface->name);
1001 }
1002
1003 THREAD_OFF(group->t_group_timer);
1004 zassert(!group->t_group_timer);
1005 }
1006
1007 void igmp_group_timer_on(struct igmp_group *group,
1008 long interval_msec, const char *ifname)
1009 {
1010 group_timer_off(group);
1011
1012 if (PIM_DEBUG_IGMP_EVENTS) {
1013 char group_str[INET_ADDRSTRLEN];
1014 pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
1015 zlog_debug("Scheduling %ld.%03ld sec TIMER event for group %s on %s",
1016 interval_msec / 1000,
1017 interval_msec % 1000,
1018 group_str, ifname);
1019 }
1020
1021 /*
1022 RFC 3376: 6.2.2. Definition of Group Timers
1023
1024 The group timer is only used when a group is in EXCLUDE mode and
1025 it represents the time for the *filter-mode* of the group to
1026 expire and switch to INCLUDE mode.
1027 */
1028 zassert(group->group_filtermode_isexcl);
1029
1030 thread_add_timer_msec(master, igmp_group_timer, group, interval_msec,
1031 &group->t_group_timer);
1032 }
1033
1034 struct igmp_group *
1035 find_group_by_addr (struct igmp_sock *igmp,
1036 struct in_addr group_addr)
1037 {
1038 struct igmp_group lookup;
1039
1040 lookup.group_addr.s_addr = group_addr.s_addr;
1041
1042 return hash_lookup(igmp->igmp_group_hash, &lookup);
1043 }
1044
1045 struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp,
1046 struct in_addr group_addr)
1047 {
1048 struct igmp_group *group;
1049
1050 group = find_group_by_addr(igmp, group_addr);
1051 if (group) {
1052 return group;
1053 }
1054
1055 if (!pim_is_group_224_4 (group_addr))
1056 {
1057 zlog_warn("%s: Group Specified is not part of 224.0.0.0/4",
1058 __PRETTY_FUNCTION__);
1059 return NULL;
1060 }
1061
1062 if (pim_is_group_224_0_0_0_24 (group_addr))
1063 {
1064 zlog_warn("%s: Group specified is part of 224.0.0.0/24",
1065 __PRETTY_FUNCTION__);
1066 return NULL;
1067 }
1068 /*
1069 Non-existant group is created as INCLUDE {empty}:
1070
1071 RFC 3376 - 5.1. Action on Change of Interface State
1072
1073 If no interface state existed for that multicast address before
1074 the change (i.e., the change consisted of creating a new
1075 per-interface record), or if no state exists after the change
1076 (i.e., the change consisted of deleting a per-interface record),
1077 then the "non-existent" state is considered to have a filter mode
1078 of INCLUDE and an empty source list.
1079 */
1080
1081 group = XCALLOC(MTYPE_PIM_IGMP_GROUP, sizeof(*group));
1082 if (!group) {
1083 zlog_warn("%s %s: XCALLOC() failure",
1084 __FILE__, __PRETTY_FUNCTION__);
1085 return NULL; /* error, not found, could not create */
1086 }
1087
1088 group->group_source_list = list_new();
1089 if (!group->group_source_list) {
1090 zlog_warn("%s %s: list_new() failure",
1091 __FILE__, __PRETTY_FUNCTION__);
1092 XFREE(MTYPE_PIM_IGMP_GROUP, group); /* discard group */
1093 return NULL; /* error, not found, could not initialize */
1094 }
1095 group->group_source_list->del = (void (*)(void *)) igmp_source_free;
1096
1097 group->t_group_timer = NULL;
1098 group->t_group_query_retransmit_timer = NULL;
1099 group->group_specific_query_retransmit_count = 0;
1100 group->group_addr = group_addr;
1101 group->group_igmp_sock = igmp;
1102 group->last_igmp_v1_report_dsec = -1;
1103 group->last_igmp_v2_report_dsec = -1;
1104 group->group_creation = pim_time_monotonic_sec();
1105 group->igmp_version = IGMP_DEFAULT_VERSION;
1106
1107 /* initialize new group as INCLUDE {empty} */
1108 group->group_filtermode_isexcl = 0; /* 0=INCLUDE, 1=EXCLUDE */
1109
1110 listnode_add(igmp->igmp_group_list, group);
1111 group = hash_get (igmp->igmp_group_hash, group, hash_alloc_intern);
1112
1113 if (PIM_DEBUG_IGMP_TRACE) {
1114 char group_str[INET_ADDRSTRLEN];
1115 pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
1116 zlog_debug("Creating new IGMP group %s on socket %d interface %s",
1117 group_str, igmp->fd, igmp->interface->name);
1118 }
1119
1120 /*
1121 RFC 3376: 6.2.2. Definition of Group Timers
1122
1123 The group timer is only used when a group is in EXCLUDE mode and
1124 it represents the time for the *filter-mode* of the group to
1125 expire and switch to INCLUDE mode.
1126 */
1127 zassert(!group->group_filtermode_isexcl); /* INCLUDE mode */
1128 zassert(!group->t_group_timer); /* group timer == 0 */
1129
1130 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
1131 igmp_anysource_forward_stop(group);
1132
1133 return group;
1134 }
1135
1136 void
1137 igmp_send_query (int igmp_version,
1138 struct igmp_group *group,
1139 int fd,
1140 const char *ifname,
1141 char *query_buf,
1142 int query_buf_size,
1143 int num_sources,
1144 struct in_addr dst_addr,
1145 struct in_addr group_addr,
1146 int query_max_response_time_dsec,
1147 uint8_t s_flag,
1148 uint8_t querier_robustness_variable,
1149 uint16_t querier_query_interval)
1150 {
1151 if (igmp_version == 3) {
1152 igmp_v3_send_query (group, fd, ifname, query_buf,
1153 query_buf_size, num_sources,
1154 dst_addr, group_addr,
1155 query_max_response_time_dsec, s_flag,
1156 querier_robustness_variable,
1157 querier_query_interval);
1158 } else if (igmp_version == 2) {
1159 igmp_v2_send_query (group, fd, ifname, query_buf,
1160 dst_addr, group_addr,
1161 query_max_response_time_dsec);
1162 }
1163 }