diff options
Diffstat (limited to 'pimd')
| -rw-r--r-- | pimd/pim_cmd.c | 60 | ||||
| -rw-r--r-- | pimd/pim_iface.c | 13 | ||||
| -rw-r--r-- | pimd/pim_igmp.c | 69 | ||||
| -rw-r--r-- | pimd/pim_igmp.h | 6 | ||||
| -rw-r--r-- | pimd/pim_nb_config.c | 2 | ||||
| -rw-r--r-- | pimd/pim_neighbor.c | 8 | ||||
| -rw-r--r-- | pimd/pim_rp.c | 33 | ||||
| -rw-r--r-- | pimd/pim_sock.c | 18 |
8 files changed, 154 insertions, 55 deletions
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index cc11a3cc17..37d206cc11 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -497,6 +497,7 @@ static void igmp_show_interfaces(struct pim_instance *pim, struct vty *vty, struct interface *ifp; time_t now; char buf[PREFIX_STRLEN]; + char quer_buf[PREFIX_STRLEN]; json_object *json = NULL; json_object *json_row = NULL; @@ -506,7 +507,7 @@ static void igmp_show_interfaces(struct pim_instance *pim, struct vty *vty, json = json_object_new_object(); else vty_out(vty, - "Interface State Address V Querier Query Timer Uptime\n"); + "Interface State Address V Querier QuerierIp Query Timer Uptime\n"); FOR_ALL_INTERFACES (pim->vrf, ifp) { struct pim_interface *pim_ifp; @@ -544,6 +545,10 @@ static void igmp_show_interfaces(struct pim_instance *pim, struct vty *vty, "queryTimer", query_hhmmss); } + json_object_string_add( + json_row, "querierIp", + inet_ntop(AF_INET, &igmp->querier_addr, + quer_buf, sizeof(quer_buf))); json_object_object_add(json, ifp->name, json_row); @@ -554,18 +559,19 @@ static void igmp_show_interfaces(struct pim_instance *pim, struct vty *vty, } } else { vty_out(vty, - "%-16s %5s %15s %d %7s %11s %8s\n", + "%-16s %5s %15s %d %7s %17pI4 %11s %8s\n", ifp->name, if_is_up(ifp) - ? (igmp->mtrace_only ? "mtrc" - : "up") - : "down", - inet_ntop(AF_INET, &igmp->ifaddr, - buf, sizeof(buf)), + ? (igmp->mtrace_only ? "mtrc" + : "up") + : "down", + inet_ntop(AF_INET, &igmp->ifaddr, buf, + sizeof(buf)), pim_ifp->igmp_version, igmp->t_igmp_query_timer ? "local" - : "other", - query_hhmmss, uptime); + : "other", + &igmp->querier_addr, query_hhmmss, + uptime); } } } @@ -586,6 +592,7 @@ static void igmp_show_interfaces_single(struct pim_instance *pim, struct listnode *sock_node; struct pim_interface *pim_ifp; char uptime[10]; + char quer_buf[PREFIX_STRLEN]; char query_hhmmss[10]; char other_hhmmss[10]; int found_ifname = 0; @@ -670,6 +677,10 @@ static void igmp_show_interfaces_single(struct pim_instance *pim, igmp->t_igmp_query_timer ? "local" : "other"); + json_object_string_add( + json_row, "querierIp", + inet_ntop(AF_INET, &igmp->querier_addr, + quer_buf, sizeof(quer_buf))); json_object_int_add(json_row, "queryStartCount", igmp->startup_query_count); json_object_string_add(json_row, @@ -739,6 +750,14 @@ static void igmp_show_interfaces_single(struct pim_instance *pim, vty_out(vty, "Querier : %s\n", igmp->t_igmp_query_timer ? "local" : "other"); + vty_out(vty, "QuerierIp : %pI4", + &igmp->querier_addr); + if (pim_ifp->primary_address.s_addr + == igmp->querier_addr.s_addr) + vty_out(vty, " (this router)\n"); + else + vty_out(vty, "\n"); + vty_out(vty, "Start Count : %d\n", igmp->startup_query_count); vty_out(vty, "Query Timer : %s\n", @@ -1135,6 +1154,12 @@ static void pim_show_interfaces_single(struct pim_instance *pim, json_object_int_add( json_row, "overrideIntervalHighest", pim_ifp->pim_neighbors_highest_override_interval_msec); + if (pim_ifp->bsm_enable) + json_object_boolean_true_add(json_row, + "bsmEnabled"); + if (pim_ifp->ucast_bsm_accept) + json_object_boolean_true_add(json_row, + "ucastBsmEnabled"); json_object_object_add(json, ifp->name, json_row); } else { @@ -1289,6 +1314,15 @@ static void pim_show_interfaces_single(struct pim_instance *pim, pim_ifp->pim_neighbors_highest_override_interval_msec); vty_out(vty, "\n"); vty_out(vty, "\n"); + + vty_out(vty, "BSM Status\n"); + vty_out(vty, "----------\n"); + vty_out(vty, "Bsm Enabled : %s\n", + pim_ifp->bsm_enable ? "yes" : "no"); + vty_out(vty, "Unicast Bsm Enabled : %s\n", + pim_ifp->ucast_bsm_accept ? "yes" : "no"); + vty_out(vty, "\n"); + vty_out(vty, "\n"); } } @@ -7153,7 +7187,7 @@ DEFPY (pim_register_accept_list, DEFUN (ip_pim_joinprune_time, ip_pim_joinprune_time_cmd, - "ip pim join-prune-interval (60-600)", + "ip pim join-prune-interval (5-600)", IP_STR "pim multicast routing\n" "Join Prune Send Interval\n" @@ -7167,7 +7201,7 @@ DEFUN (ip_pim_joinprune_time, DEFUN (no_ip_pim_joinprune_time, no_ip_pim_joinprune_time_cmd, - "no ip pim join-prune-interval (60-600)", + "no ip pim join-prune-interval (5-600)", NO_STR IP_STR "pim multicast routing\n" @@ -8752,7 +8786,7 @@ DEFUN (interface_no_ip_mroute, DEFUN (interface_ip_pim_hello, interface_ip_pim_hello_cmd, - "ip pim hello (1-180) [(1-180)]", + "ip pim hello (1-180) [(1-630)]", IP_STR PIM_STR IFACE_PIM_HELLO_STR @@ -8787,7 +8821,7 @@ DEFUN (interface_ip_pim_hello, DEFUN (interface_no_ip_pim_hello, interface_no_ip_pim_hello_cmd, - "no ip pim hello [(1-180) [(1-180)]]", + "no ip pim hello [(1-180) [(1-630)]]", NO_STR IP_STR PIM_STR diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 48b019c8c8..0b28a3e84c 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -1512,10 +1512,15 @@ struct prefix *pim_if_connected_to_source(struct interface *ifp, struct in_addr p.prefixlen = IPV4_MAX_BITLEN; for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { - if ((c->address->family == AF_INET) - && prefix_match(CONNECTED_PREFIX(c), &p)) { - return CONNECTED_PREFIX(c); - } + if (c->address->family != AF_INET) + continue; + if (prefix_match(c->address, &p)) + return c->address; + if (CONNECTED_PEER(c) && prefix_match(c->destination, &p)) + /* this is not a typo, on PtP we need to return the + * *local* address that lines up with src. + */ + return c->address; } return NULL; diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 73dcdbddb4..426112d4d6 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -167,6 +167,8 @@ static int pim_igmp_other_querier_expire(struct thread *t) sizeof(ifaddr_str)); zlog_debug("%s: Querier %s resuming", __func__, ifaddr_str); } + /* Mark the interface address as querier address */ + igmp->querier_addr = igmp->ifaddr; /* We are the current querier, then @@ -397,6 +399,8 @@ static int igmp_recv_query(struct igmp_sock *igmp, int query_version, ntohl(igmp->ifaddr.s_addr), from_str, ntohl(from.s_addr)); } + if (ntohl(from.s_addr) < ntohl(igmp->querier_addr.s_addr)) + igmp->querier_addr.s_addr = from.s_addr; pim_igmp_other_querier_timer_on(igmp); } @@ -469,47 +473,83 @@ static int igmp_v1_recv_report(struct igmp_sock *igmp, struct in_addr from, return 0; } -int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len) +bool pim_igmp_verify_header(struct ip *ip_hdr, size_t len, size_t *hlen) { - struct ip *ip_hdr; - size_t ip_hlen; /* ip header length in bytes */ char *igmp_msg; int igmp_msg_len; int msg_type; - char from_str[INET_ADDRSTRLEN]; - char to_str[INET_ADDRSTRLEN]; + size_t ip_hlen; /* ip header length in bytes */ if (len < sizeof(*ip_hdr)) { zlog_warn("IGMP packet size=%zu shorter than minimum=%zu", len, sizeof(*ip_hdr)); - return -1; + return false; } - ip_hdr = (struct ip *)buf; - - pim_inet4_dump("<src?>", ip_hdr->ip_src, from_str, sizeof(from_str)); - pim_inet4_dump("<dst?>", ip_hdr->ip_dst, to_str, sizeof(to_str)); - ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */ + *hlen = ip_hlen; if (ip_hlen > len) { zlog_warn( "IGMP packet header claims size %zu, but we only have %zu bytes", ip_hlen, len); - return -1; + return false; } - igmp_msg = buf + ip_hlen; + igmp_msg = (char *)ip_hdr + ip_hlen; igmp_msg_len = len - ip_hlen; + msg_type = *igmp_msg; if (igmp_msg_len < PIM_IGMP_MIN_LEN) { zlog_warn("IGMP message size=%d shorter than minimum=%d", igmp_msg_len, PIM_IGMP_MIN_LEN); - return -1; + return false; + } + + if ((msg_type != PIM_IGMP_MTRACE_RESPONSE) + && (msg_type != PIM_IGMP_MTRACE_QUERY_REQUEST)) { + if (ip_hdr->ip_ttl != 1) { + zlog_warn( + "Recv IGMP packet with invalid ttl=%u, discarding the packet", + ip_hdr->ip_ttl); + return -1; + } } + if ((msg_type == PIM_IGMP_V3_MEMBERSHIP_REPORT) + || ((msg_type == PIM_IGMP_MEMBERSHIP_QUERY) + && (igmp_msg_len >= IGMP_V3_SOURCES_OFFSET))) { + /* All IGMPv3 messages must be received with TOS set to 0xC0*/ + if (ip_hdr->ip_tos != IPTOS_PREC_INTERNETCONTROL) { + zlog_warn("Received IGMP Packet with invalid TOS %u", + ip_hdr->ip_tos); + return -1; + } + } + + return true; +} + +int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len) +{ + struct ip *ip_hdr = (struct ip *)buf; + size_t ip_hlen; /* ip header length in bytes */ + char *igmp_msg; + int igmp_msg_len; + int msg_type; + char from_str[INET_ADDRSTRLEN]; + char to_str[INET_ADDRSTRLEN]; + + if (!pim_igmp_verify_header(ip_hdr, len, &ip_hlen)) + return -1; + + igmp_msg = buf + ip_hlen; + igmp_msg_len = len - ip_hlen; msg_type = *igmp_msg; + pim_inet4_dump("<src?>", ip_hdr->ip_src, from_str, sizeof(from_str)); + pim_inet4_dump("<dst?>", ip_hdr->ip_dst, to_str, sizeof(to_str)); + if (PIM_DEBUG_IGMP_PACKETS) { zlog_debug( "Recv IGMP packet from %s to %s on %s: size=%zu ttl=%d msg_type=%d msg_size=%d", @@ -935,6 +975,7 @@ static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr, igmp->fd = fd; igmp->interface = ifp; igmp->ifaddr = ifaddr; + igmp->querier_addr = ifaddr; igmp->t_igmp_read = NULL; igmp->t_igmp_query_timer = NULL; igmp->t_other_querier_timer = NULL; /* no other querier present */ diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h index a0681128c0..abb8af836b 100644 --- a/pimd/pim_igmp.h +++ b/pimd/pim_igmp.h @@ -92,8 +92,8 @@ struct igmp_sock { struct thread *t_igmp_query_timer; /* timer: issue IGMP general queries */ struct thread *t_other_querier_timer; /* timer: other querier present */ - - int querier_query_interval; /* QQI */ + struct in_addr querier_addr; /* IP address of the querier */ + int querier_query_interval; /* QQI */ int querier_robustness_variable; /* QRV */ int startup_query_count; @@ -116,7 +116,7 @@ void igmp_sock_delete(struct igmp_sock *igmp); void igmp_sock_free(struct igmp_sock *igmp); void igmp_sock_delete_all(struct interface *ifp); int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len); - +bool pim_igmp_verify_header(struct ip *ip_hdr, size_t len, size_t *ip_hlen); void pim_igmp_general_query_on(struct igmp_sock *igmp); void pim_igmp_general_query_off(struct igmp_sock *igmp); void pim_igmp_other_querier_timer_on(struct igmp_sock *igmp); diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index dfdbd6dee2..bd5e215027 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -1613,7 +1613,7 @@ int lib_interface_pim_hello_holdtime_modify(struct nb_cb_modify_args *args) ifp = nb_running_get_entry(args->dnode, NULL, true); pim_ifp = ifp->info; pim_ifp->pim_default_holdtime = - yang_dnode_get_uint8(args->dnode, NULL); + yang_dnode_get_uint16(args->dnode, NULL); break; } diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index 48b1a30f2d..571173c62a 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -350,8 +350,8 @@ pim_neighbor_new(struct interface *ifp, struct in_addr source_addr, __func__, src_str, ifp->name); } - zlog_info("PIM NEIGHBOR UP: neighbor %s on interface %s", src_str, - ifp->name); + zlog_notice("PIM NEIGHBOR UP: neighbor %s on interface %s", src_str, + ifp->name); if (neigh->propagation_delay_msec > pim_ifp->pim_neighbors_highest_propagation_delay_msec) { @@ -616,8 +616,8 @@ void pim_neighbor_delete(struct interface *ifp, struct pim_neighbor *neigh, assert(pim_ifp); pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str)); - zlog_info("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s", src_str, - ifp->name, delete_message); + zlog_notice("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s", + src_str, ifp->name, delete_message); THREAD_OFF(neigh->t_expire_timer); diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index b6521132f7..56e1927528 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -204,6 +204,26 @@ static struct rp_info *pim_rp_find_exact(struct pim_instance *pim, } /* + * XXX: long-term issue: we don't actually have a good "ip address-list" + * implementation. ("access-list XYZ" is the closest but honestly it's + * kinda garbage.) + * + * So it's using a prefix-list to match an address here, which causes very + * unexpected results for the user since prefix-lists by default only match + * when the prefix length is an exact match too. i.e. you'd have to add the + * "le 32" and do "ip prefix-list foo permit 10.0.0.0/24 le 32" + * + * To avoid this pitfall, this code uses "address_mode = true" for the prefix + * list match (this is the only user for that.) + * + * In the long run, we need to add a "ip address-list", but that's a wholly + * separate bag of worms, and existing configs using ip prefix-list would + * drop into the UX pitfall. + */ + +#include "lib/plist_int.h" + +/* * Given a group, return the rp_info for that group */ struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, @@ -213,7 +233,8 @@ struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, struct rp_info *best = NULL; struct rp_info *rp_info; struct prefix_list *plist; - const struct prefix *p, *bp; + const struct prefix *bp; + const struct prefix_list_entry *entry; struct route_node *rn; bp = NULL; @@ -221,19 +242,19 @@ struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, if (rp_info->plist) { plist = prefix_list_lookup(AFI_IP, rp_info->plist); - if (prefix_list_apply_which_prefix(plist, &p, group) - == PREFIX_DENY) + if (prefix_list_apply_ext(plist, &entry, group, true) + == PREFIX_DENY || !entry) continue; if (!best) { best = rp_info; - bp = p; + bp = &entry->prefix; continue; } - if (bp && bp->prefixlen < p->prefixlen) { + if (bp && bp->prefixlen < entry->prefix.prefixlen) { best = rp_info; - bp = p; + bp = &entry->prefix; } } } diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index 504519c8a4..05b0f92a4b 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -112,17 +112,15 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, struct interface *ifp, } #ifdef SO_BINDTODEVICE - if (protocol == IPPROTO_PIM) { - int ret; + int ret; - ret = pim_socket_bind(fd, ifp); - if (ret) { - close(fd); - zlog_warn( - "Could not set fd: %d for interface: %s to device", - fd, ifp->name); - return PIM_SOCK_ERR_BIND; - } + ret = pim_socket_bind(fd, ifp); + if (ret) { + close(fd); + zlog_warn( + "Could not set fd: %d for interface: %s to device", + fd, ifp->name); + return PIM_SOCK_ERR_BIND; } #else /* XXX: use IP_PKTINFO / IP_RECVIF to emulate behaviour? Or change to |
