diff options
| -rw-r--r-- | pimd/pim6_mld.c | 70 | ||||
| -rw-r--r-- | pimd/pim6_mld.h | 37 |
2 files changed, 100 insertions, 7 deletions
diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c index 5ba5fd35bc..6de16a5a58 100644 --- a/pimd/pim6_mld.c +++ b/pimd/pim6_mld.c @@ -224,6 +224,7 @@ static struct gm_sg *gm_sg_make(struct gm_if *gm_ifp, pim_addr grp, XFREE(MTYPE_GM_SG, ret); ret = prev; } else { + monotime(&ret->created); gm_packet_sg_subs_init(ret->subs_positive); gm_packet_sg_subs_init(ret->subs_negative); } @@ -285,6 +286,7 @@ static struct gm_subscriber *gm_subscriber_get(struct gm_if *gm_ifp, ret->iface = gm_ifp; ret->addr = addr; ret->refcount = 1; + monotime(&ret->created); gm_packets_init(ret->packets); gm_subscribers_add(gm_ifp->subscribers, ret); @@ -815,9 +817,13 @@ static void gm_handle_v2_report(struct gm_if *gm_ifp, if (PIM_DEBUG_IGMP_PACKETS) zlog_debug(log_pkt_src( "malformed MLDv2 report (truncated header)")); + gm_ifp->stats.rx_drop_malformed++; return; } + /* errors after this may at least partially process the packet */ + gm_ifp->stats.rx_new_report++; + hdr = (struct mld_v2_report_hdr *)data; data += sizeof(*hdr); len -= sizeof(*hdr); @@ -842,6 +848,7 @@ static void gm_handle_v2_report(struct gm_if *gm_ifp, if (len < sizeof(*rechdr)) { zlog_warn(log_pkt_src( "malformed MLDv2 report (truncated record header)")); + gm_ifp->stats.rx_trunc_report++; break; } @@ -855,6 +862,7 @@ static void gm_handle_v2_report(struct gm_if *gm_ifp, if (len < record_size) { zlog_warn(log_pkt_src( "malformed MLDv2 report (truncated source list)")); + gm_ifp->stats.rx_trunc_report++; break; } if (!IN6_IS_ADDR_MULTICAST(&rechdr->grp)) { @@ -862,6 +870,7 @@ static void gm_handle_v2_report(struct gm_if *gm_ifp, log_pkt_src( "malformed MLDv2 report (invalid group %pI6)"), &rechdr->grp); + gm_ifp->stats.rx_trunc_report++; break; } @@ -913,9 +922,12 @@ static void gm_handle_v1_report(struct gm_if *gm_ifp, if (len < sizeof(*hdr)) { if (PIM_DEBUG_IGMP_PACKETS) zlog_debug(log_pkt_src("malformed MLDv1 report (truncated)")); + gm_ifp->stats.rx_drop_malformed++; return; } + gm_ifp->stats.rx_old_report++; + hdr = (struct mld_v1_pkt *)data; max_entries = 1; @@ -975,9 +987,12 @@ static void gm_handle_v1_leave(struct gm_if *gm_ifp, if (len < sizeof(*hdr)) { if (PIM_DEBUG_IGMP_PACKETS) zlog_debug(log_pkt_src("malformed MLDv1 leave (truncated)")); + gm_ifp->stats.rx_drop_malformed++; return; } + gm_ifp->stats.rx_old_leave++; + hdr = (struct mld_v1_pkt *)data; subscriber = gm_subscriber_findref(gm_ifp, gm_dummy_untracked); @@ -1363,6 +1378,7 @@ static void gm_handle_query(struct gm_if *gm_ifp, if (len < sizeof(struct mld_v2_query_hdr) && len != sizeof(struct mld_v1_pkt)) { zlog_warn(log_pkt_src("invalid query size")); + gm_ifp->stats.rx_drop_malformed++; return; } @@ -1373,6 +1389,7 @@ static void gm_handle_query(struct gm_if *gm_ifp, zlog_warn(log_pkt_src( "malformed MLDv2 query (invalid group %pI6)"), &hdr->grp); + gm_ifp->stats.rx_drop_malformed++; return; } @@ -1382,12 +1399,14 @@ static void gm_handle_query(struct gm_if *gm_ifp, if (len < sizeof(struct mld_v2_query_hdr) + src_space) { zlog_warn(log_pkt_src( "malformed MLDv2 query (truncated source list)")); + gm_ifp->stats.rx_drop_malformed++; return; } if (general_query && src_space) { zlog_warn(log_pkt_src( "malformed MLDv2 query (general query with non-empty source list)")); + gm_ifp->stats.rx_drop_malformed++; return; } } @@ -1402,10 +1421,12 @@ static void gm_handle_query(struct gm_if *gm_ifp, log_pkt_src( "wrong destination %pPA for general query"), pkt_dst); + gm_ifp->stats.rx_drop_dstaddr++; return; } if (!IPV6_ADDR_SAME(&hdr->grp, pkt_dst)) { + gm_ifp->stats.rx_drop_dstaddr++; zlog_warn( log_pkt_src( "wrong destination %pPA for group specific query"), @@ -1454,24 +1475,33 @@ static void gm_handle_query(struct gm_if *gm_ifp, } if (len == sizeof(struct mld_v1_pkt)) { - if (general_query) + if (general_query) { gm_handle_q_general(gm_ifp, &timers); - else + gm_ifp->stats.rx_query_old_general++; + } else { gm_handle_q_group(gm_ifp, &timers, hdr->grp); + gm_ifp->stats.rx_query_old_group++; + } return; } /* v2 query - [S]uppress bit */ - if (hdr->flags & 0x8) + if (hdr->flags & 0x8) { + gm_ifp->stats.rx_query_new_sbit++; return; + } - if (general_query) + if (general_query) { gm_handle_q_general(gm_ifp, &timers); - else if (!ntohs(hdr->n_src)) + gm_ifp->stats.rx_query_new_general++; + } else if (!ntohs(hdr->n_src)) { gm_handle_q_group(gm_ifp, &timers, hdr->grp); - else + gm_ifp->stats.rx_query_new_group++; + } else { gm_handle_q_groupsrc(gm_ifp, &timers, hdr->grp, hdr->srcs, ntohs(hdr->n_src)); + gm_ifp->stats.rx_query_new_groupsrc++; + } } static void gm_rx_process(struct gm_if *gm_ifp, @@ -1496,6 +1526,7 @@ static void gm_rx_process(struct gm_if *gm_ifp, log_pkt_src( "(dst %pPA) packet RX checksum failure, expected %04hx, got %04hx"), pkt_dst, pkt_csum, ref_csum); + gm_ifp->stats.rx_drop_csum++; return; } @@ -1592,6 +1623,7 @@ static void gm_t_recv(struct thread *t) nread = recvmsg(gm_ifp->sock, mh, MSG_PEEK | MSG_TRUNC); if (nread <= 0) { zlog_err(log_ifp("RX error: %m")); + gm_ifp->stats.rx_drop_sys++; return; } @@ -1602,6 +1634,7 @@ static void gm_t_recv(struct thread *t) nread = recvmsg(gm_ifp->sock, mh, 0); if (nread <= 0) { zlog_err(log_ifp("RX error: %m")); + gm_ifp->stats.rx_drop_sys++; goto out_free; } @@ -1629,17 +1662,21 @@ static void gm_t_recv(struct thread *t) if (!pktinfo || !hoplimit) { zlog_err(log_ifp( "BUG: packet without IPV6_PKTINFO or IPV6_HOPLIMIT")); + gm_ifp->stats.rx_drop_sys++; goto out_free; } if (*hoplimit != 1) { zlog_err(log_pkt_src("packet with hop limit != 1")); + /* spoofing attempt => count on srcaddr counter */ + gm_ifp->stats.rx_drop_srcaddr++; goto out_free; } if (!ip6_check_hopopts_ra(hopopts, hopopt_len, IP6_ALERT_MLD)) { zlog_err(log_pkt_src( "packet without IPv6 Router Alert MLD option")); + gm_ifp->stats.rx_drop_ra++; goto out_free; } @@ -1651,12 +1688,14 @@ static void gm_t_recv(struct thread *t) if (!IN6_IS_ADDR_LINKLOCAL(&pkt_src->sin6_addr)) { zlog_warn(log_pkt_src("packet from invalid source address")); + gm_ifp->stats.rx_drop_srcaddr++; goto out_free; } pktlen = nread; if (pktlen < sizeof(struct icmp6_plain_hdr)) { zlog_warn(log_pkt_src("truncated packet")); + gm_ifp->stats.rx_drop_malformed++; goto out_free; } @@ -1777,8 +1816,24 @@ static void gm_send_query(struct gm_if *gm_ifp, pim_addr grp, ret = sendmsg(gm_ifp->sock, mh, 0); } - if (ret != expect_ret) + if (ret != expect_ret) { zlog_warn(log_ifp("failed to send query: %m")); + gm_ifp->stats.tx_query_fail++; + } else { + if (gm_ifp->cur_version == GM_MLDV1) { + if (pim_addr_is_any(grp)) + gm_ifp->stats.tx_query_old_general++; + else + gm_ifp->stats.tx_query_old_group++; + } else { + if (pim_addr_is_any(grp)) + gm_ifp->stats.tx_query_new_general++; + else if (!n_srcs) + gm_ifp->stats.tx_query_new_group++; + else + gm_ifp->stats.tx_query_new_groupsrc++; + } + } } static void gm_t_query(struct thread *t) @@ -1894,6 +1949,7 @@ static void gm_start(struct interface *ifp) gm_ifp->ifp = ifp; pim_ifp->mld = gm_ifp; gm_ifp->pim = pim_ifp->pim; + monotime(&gm_ifp->started); zlog_info(log_ifp("starting MLD")); diff --git a/pimd/pim6_mld.h b/pimd/pim6_mld.h index 52f7405f82..cd50dcacac 100644 --- a/pimd/pim6_mld.h +++ b/pimd/pim6_mld.h @@ -70,6 +70,8 @@ struct gm_sg { struct channel_oil *oil; bool tib_joined; + struct timeval created; + /* if a group- or group-and-source specific query is running * (implies we haven't received any report yet, since it's cancelled * by that) @@ -142,6 +144,8 @@ struct gm_subscriber { size_t refcount; struct gm_packets_head packets[1]; + + struct timeval created; }; /* @@ -275,6 +279,36 @@ enum gm_version { GM_MLDV2, }; +struct gm_if_stats { + uint64_t rx_drop_sys; + uint64_t rx_drop_csum; + uint64_t rx_drop_srcaddr; + uint64_t rx_drop_dstaddr; + uint64_t rx_drop_ra; + uint64_t rx_drop_malformed; + uint64_t rx_trunc_report; + + /* since the types are different, this is rx_old_* not of rx_*_old */ + uint64_t rx_old_report; + uint64_t rx_old_leave; + uint64_t rx_new_report; + + uint64_t rx_query_new_general; + uint64_t rx_query_new_group; + uint64_t rx_query_new_groupsrc; + uint64_t rx_query_new_sbit; + uint64_t rx_query_old_general; + uint64_t rx_query_old_group; + + uint64_t tx_query_new_general; + uint64_t tx_query_new_group; + uint64_t tx_query_new_groupsrc; + uint64_t tx_query_old_general; + uint64_t tx_query_old_group; + + uint64_t tx_query_fail; +}; + struct gm_if { struct interface *ifp; struct pim_instance *pim; @@ -311,6 +345,9 @@ struct gm_if { struct gm_sgs_head sgs[1]; struct gm_subscribers_head subscribers[1]; struct gm_packet_expires_head expires[1]; + + struct timeval started; + struct gm_if_stats stats; }; #if PIM_IPV == 6 |
