summaryrefslogtreecommitdiff
path: root/pimd
diff options
context:
space:
mode:
Diffstat (limited to 'pimd')
-rw-r--r--pimd/pim_cmd.c60
-rw-r--r--pimd/pim_iface.c13
-rw-r--r--pimd/pim_igmp.c69
-rw-r--r--pimd/pim_igmp.h6
-rw-r--r--pimd/pim_nb_config.c2
-rw-r--r--pimd/pim_neighbor.c8
-rw-r--r--pimd/pim_rp.c33
-rw-r--r--pimd/pim_sock.c18
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