pimd: adding querying of state to mtrace

Adding to mtracebis querying with group address. Same change
to vtysh mtrace command. Support for querying (S,G) and (*,G)
state in mtrace router code. Further improvments to mtrace router
code with closer complience to IETF draft. More references in
comments to the draft. Man page has been updated accordingly.

Signed-off-by: Mladen Sablic <mladen.sablic@gmail.com>
This commit is contained in:
Mladen Sablic 2018-04-12 13:24:21 +02:00
parent 8aeee10fe2
commit 71e55fb257
5 changed files with 234 additions and 68 deletions

View File

@ -9,17 +9,22 @@ SYNOPSIS
========
|PROGRAM| |synopsis-options-hv|
|PROGRAM| <multicast source>
|PROGRAM| <multicast source> [<multicast group>]
DESCRIPTION
===========
|PROGRAM| is a program to initiate multicast traceroute, or "mtrace", queries.
|PROGRAM| is a program for initiating multicast traceroute, or "mtrace", queries.
The initial version of the program requires multicast source IP address and
initiates a weak traceroute across the network. This tests whether the
interfaces towards the source are multicast enabled. The first query sent is a
full query, capable of crossing the network all the way to the source. If this
fails, hop-by-hop queries are initiated.
It can initiate two types of mtrace queries: weak and group.
Weak tests whether the interfaces towards the source are multicast enabled and is
initiated by supplying only the multicast source address.
Group tests whether there is multicast routing protocol state for particular
multicast group and is initiated by supplying mutlicast source and group.
The first query sent is a full query, capable of crossing the network all the way
to the source. If this fails, hop-by-hop queries are initiated.
Hop-by-hop queries start by requesting only a response from the nearest router.
Following that, next query is extended to the next two routers, and so on...

View File

@ -22,6 +22,7 @@
#include "pim_igmp_mtrace.h"
#include "checksum.h"
#include "prefix.h"
#include "mtracebis_routeget.h"
#include <sys/select.h>
@ -50,7 +51,8 @@
static const char *progname;
static void usage(void)
{
fprintf(stderr, "Usage : %s <multicast source>\n", progname);
fprintf(stderr, "Usage : %s <multicast source> [<multicast group>]\n",
progname);
}
static void version(void)
{
@ -170,9 +172,21 @@ static void print_fwd_code(uint32_t fwd_code)
static void print_rsp(struct igmp_mtrace_rsp *rsp)
{
print_host(rsp->outgoing);
if (rsp->fwd_code == 0) {
if (rsp->fwd_code == 0 || rsp->fwd_code == MTRACE_FWD_CODE_REACHED_RP) {
print_rtg_proto(rsp->rtg_proto);
printf(" ");
if (rsp->fwd_code == MTRACE_FWD_CODE_REACHED_RP)
printf("(RP) ");
if (rsp->rtg_proto == MTRACE_RTG_PROTO_PIM) {
switch (rsp->src_mask) {
case MTRACE_SRC_MASK_GROUP:
printf("(*,G) ");
break;
case MTRACE_SRC_MASK_SOURCE:
printf("(S,G) ");
break;
}
}
print_fwd_ttl(rsp->fwd_ttl);
} else {
print_fwd_code(rsp->fwd_code);
@ -351,6 +365,7 @@ static bool check_end(struct igmp_mtrace *mtrace, int hops)
int main(int argc, char *const argv[])
{
struct in_addr mc_source;
struct in_addr mc_group;
struct in_addr iface_addr;
struct in_addr gw_addr;
struct in_addr mtrace_addr;
@ -370,6 +385,7 @@ int main(int argc, char *const argv[])
int i, j;
char ifname[IF_NAMESIZE];
char mbuf[MTRACE_BUF_LEN];
bool not_group;
mtrace_addr.s_addr = inet_addr("224.0.1.32");
@ -385,7 +401,7 @@ int main(int argc, char *const argv[])
else
progname = argv[0];
if (argc != 2) {
if (argc != 2 && argc != 3) {
usage();
exit(EXIT_FAILURE);
}
@ -416,11 +432,28 @@ int main(int argc, char *const argv[])
}
if (inet_pton(AF_INET, argv[1], &mc_source) != 1) {
usage();
fprintf(stderr, "%s: %s not a valid IPv4 address\n", argv[0],
fprintf(stderr, "%s: %s is not a valid IPv4 address\n", argv[0],
argv[1]);
exit(EXIT_FAILURE);
}
mc_group.s_addr = 0;
not_group = false;
if (argc == 3) {
if (inet_pton(AF_INET, argv[2], &mc_group) != 1)
not_group = true;
if (!not_group && !IPV4_CLASS_DE(ntohl(mc_group.s_addr)))
not_group = true;
}
if (not_group) {
usage();
fprintf(stderr, "%s: %s is not a valid IPv4 group address\n",
argv[0], argv[2]);
exit(EXIT_FAILURE);
}
ifindex = routeget(mc_source, &iface_addr, &gw_addr);
if (ifindex < 0) {
fprintf(stderr, "%s: failed to get route to source %s\n",
@ -441,7 +474,7 @@ int main(int argc, char *const argv[])
mtrace.type = PIM_IGMP_MTRACE_QUERY_REQUEST;
mtrace.hops = hops;
mtrace.checksum = 0;
mtrace.grp_addr.s_addr = 0;
mtrace.grp_addr = mc_group;
mtrace.src_addr = mc_source;
mtrace.dst_addr = iface_addr;
mtrace.rsp_addr = unicast ? iface_addr : mtrace_addr;

View File

@ -17,6 +17,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* based on draft-ietf-idmr-traceroute-ipm-07 */
#include <zebra.h>
#include "pimd.h"
@ -56,15 +58,131 @@ static struct in_addr mtrace_primary_address(struct interface *ifp)
return any;
}
static bool mtrace_fwd_info_weak(struct pim_instance *pim,
struct igmp_mtrace *mtracep,
struct igmp_mtrace_rsp *rspp,
struct interface **ifpp)
{
struct pim_nexthop nexthop;
struct interface *ifp_in;
struct in_addr nh_addr;
int ret;
char nexthop_str[INET_ADDRSTRLEN];
nh_addr.s_addr = 0;
memset(&nexthop, 0, sizeof(nexthop));
ret = pim_nexthop_lookup(pim, &nexthop, mtracep->src_addr, 1);
if (ret != 0) {
if (PIM_DEBUG_MTRACE)
zlog_debug("mtrace not found neighbor");
return false;
}
if (PIM_DEBUG_MTRACE)
zlog_debug("mtrace pim_nexthop_lookup OK");
if (PIM_DEBUG_MTRACE)
zlog_warn("mtrace next_hop=%s",
inet_ntop(nexthop.mrib_nexthop_addr.family,
&nexthop.mrib_nexthop_addr.u.prefix,
nexthop_str, sizeof(nexthop_str)));
if (nexthop.mrib_nexthop_addr.family == AF_INET)
nh_addr = nexthop.mrib_nexthop_addr.u.prefix4;
ifp_in = nexthop.interface;
/* return interface for forwarding mtrace packets */
*ifpp = ifp_in;
/* 6.2.2. 4. Fill in the Incoming Interface Address... */
rspp->incoming = mtrace_primary_address(ifp_in);
rspp->prev_hop = nh_addr;
rspp->in_count = htonl(MTRACE_UNKNOWN_COUNT);
rspp->total = htonl(MTRACE_UNKNOWN_COUNT);
rspp->rtg_proto = MTRACE_RTG_PROTO_PIM;
return true;
}
static bool mtrace_fwd_info(struct pim_instance *pim,
struct igmp_mtrace *mtracep,
struct igmp_mtrace_rsp *rspp,
struct interface **ifpp)
{
struct prefix_sg sg;
struct pim_upstream *up;
struct interface *ifp_in;
struct in_addr nh_addr;
uint32_t total;
char up_str[INET_ADDRSTRLEN];
memset(&sg, 0, sizeof(struct prefix_sg));
sg.src = mtracep->src_addr;
sg.grp = mtracep->grp_addr;
up = pim_upstream_find(pim, &sg);
if (!up) {
sg.src.s_addr = 0;
up = pim_upstream_find(pim, &sg);
}
if (!up)
return false;
ifp_in = up->rpf.source_nexthop.interface;
nh_addr = up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4;
total = htonl(MTRACE_UNKNOWN_COUNT);
if (PIM_DEBUG_MTRACE)
zlog_debug("fwd_info: upstream next hop=%s",
inet_ntop(AF_INET, &(nh_addr), up_str,
sizeof(up_str)));
if (up->channel_oil)
total = up->channel_oil->cc.pktcnt;
/* return interface for forwarding mtrace packets */
*ifpp = ifp_in;
/* 6.2.2. 4. Fill in the Incoming Interface Address... */
rspp->incoming = mtrace_primary_address(ifp_in);
rspp->prev_hop = nh_addr;
rspp->in_count = htonl(MTRACE_UNKNOWN_COUNT);
rspp->total = total;
rspp->rtg_proto = MTRACE_RTG_PROTO_PIM;
/* 6.2.2. 4. Fill in ... S, and Src Mask */
if (sg.src.s_addr) {
rspp->s = 1;
rspp->src_mask = MTRACE_SRC_MASK_SOURCE;
} else {
rspp->s = 0;
rspp->src_mask = MTRACE_SRC_MASK_GROUP;
}
return true;
}
static void mtrace_rsp_set_fwd_code(struct igmp_mtrace_rsp *mtrace_rspp,
enum mtrace_fwd_code fwd_code)
{
if (mtrace_rspp->fwd_code == MTRACE_FWD_CODE_NO_ERROR)
mtrace_rspp->fwd_code = fwd_code;
}
static void mtrace_rsp_init(struct igmp_mtrace_rsp *mtrace_rspp)
{
mtrace_rspp->arrival = 0;
mtrace_rspp->incoming.s_addr = 0;
mtrace_rspp->outgoing.s_addr = 0;
mtrace_rspp->prev_hop.s_addr = 0;
mtrace_rspp->in_count = MTRACE_UNKNOWN_COUNT;
mtrace_rspp->out_count = MTRACE_UNKNOWN_COUNT;
mtrace_rspp->total = MTRACE_UNKNOWN_COUNT;
mtrace_rspp->in_count = htonl(MTRACE_UNKNOWN_COUNT);
mtrace_rspp->out_count = htonl(MTRACE_UNKNOWN_COUNT);
mtrace_rspp->total = htonl(MTRACE_UNKNOWN_COUNT);
mtrace_rspp->rtg_proto = 0;
mtrace_rspp->fwd_ttl = 0;
mtrace_rspp->mbz = 0;
@ -394,7 +512,6 @@ static int mtrace_forward_packet(struct pim_instance *pim, struct ip *ip_hdr)
return mtrace_un_forward_packet(pim, ip_hdr, NULL);
}
/* 6.5 Sending Traceroute Responses */
static int mtrace_send_mc_response(struct pim_instance *pim,
struct igmp_mtrace *mtracep,
size_t mtrace_len)
@ -439,6 +556,7 @@ static int mtrace_send_mc_response(struct pim_instance *pim,
return ret;
}
/* 6.5 Sending Traceroute Responses */
static int mtrace_send_response(struct pim_instance *pim,
struct igmp_mtrace *mtracep, size_t mtrace_len)
{
@ -496,7 +614,6 @@ int igmp_mtrace_recv_qry_req(struct igmp_sock *igmp, struct ip *ip_hdr,
{
static uint32_t qry_id, qry_src;
char mtrace_buf[MTRACE_HDR_SIZE + MTRACE_MAX_HOPS * MTRACE_RSP_SIZE];
struct pim_nexthop nexthop;
struct interface *ifp;
struct interface *out_ifp;
struct pim_interface *pim_ifp;
@ -505,12 +622,13 @@ int igmp_mtrace_recv_qry_req(struct igmp_sock *igmp, struct ip *ip_hdr,
struct igmp_mtrace_rsp *rspp;
struct in_addr nh_addr;
enum mtrace_fwd_code fwd_code = MTRACE_FWD_CODE_NO_ERROR;
int ret;
size_t r_len;
int last_rsp_ind = 0;
size_t mtrace_len;
uint16_t recv_checksum;
uint16_t checksum;
bool reached_source;
bool fwd_info;
ifp = igmp->interface;
pim_ifp = ifp->info;
@ -575,6 +693,8 @@ int igmp_mtrace_recv_qry_req(struct igmp_sock *igmp, struct ip *ip_hdr,
}
/* Unicast query on wrong interface */
fwd_code = MTRACE_FWD_CODE_WRONG_IF;
if (PIM_DEBUG_MTRACE)
zlog_debug("Multicast query on wrong interface");
}
if (qry_id == mtracep->qry_id && qry_src == from.s_addr) {
if (PIM_DEBUG_MTRACE)
@ -619,16 +739,19 @@ int igmp_mtrace_recv_qry_req(struct igmp_sock *igmp, struct ip *ip_hdr,
/* 6.2.2. Normal Processing */
/* 6.2.2. 1. */
/* 6.2.2. 1. If there is room in the current buffer? */
if (last_rsp_ind == MTRACE_MAX_HOPS) {
/* ...there was no room... */
mtracep->rsp[MTRACE_MAX_HOPS - 1].fwd_code =
MTRACE_FWD_CODE_NO_SPACE;
return mtrace_send_response(pim_ifp->pim, mtracep,
igmp_msg_len);
}
/* calculate new mtrace mtrace lenght with extra response */
/* ...insert new response block... */
/* calculate new mtrace lenght with extra response */
mtrace_len = igmp_msg_len + sizeof(struct igmp_mtrace_rsp);
/* copy received query/request */
@ -643,84 +766,86 @@ int igmp_mtrace_recv_qry_req(struct igmp_sock *igmp, struct ip *ip_hdr,
/* initialize extra response field */
mtrace_rsp_init(rspp);
/* carry over any error noted when receiving the query */
rspp->fwd_code = fwd_code;
/* ...and fill in Query Arrival Time... */
rspp->arrival = htonl(query_arrival_time());
rspp->outgoing = pim_ifp->primary_address;
rspp->out_count = htonl(MTRACE_UNKNOWN_COUNT);
rspp->fwd_ttl = 1;
/* 6.2.2. 2. Attempt to determine forwarding information */
/* 6.2.2. 2. Attempt to determine the forwarding information... */
nh_addr.s_addr = 0;
memset(&nexthop, 0, sizeof(nexthop));
ret = pim_nexthop_lookup(pim, &nexthop, mtracep->src_addr, 1);
if (ret == 0) {
char nexthop_str[INET_ADDRSTRLEN];
if (mtracep->grp_addr.s_addr)
fwd_info = mtrace_fwd_info(pim, mtracep, rspp, &out_ifp);
else
fwd_info = mtrace_fwd_info_weak(pim, mtracep, rspp, &out_ifp);
/* 6.2.2 3. If no forwarding information... */
if (!fwd_info) {
if (PIM_DEBUG_MTRACE)
zlog_debug("mtrace pim_nexthop_lookup OK");
if (PIM_DEBUG_MTRACE)
zlog_warn("mtrace next_hop=%s",
inet_ntop(nexthop.mrib_nexthop_addr.family,
&nexthop.mrib_nexthop_addr.u.prefix,
nexthop_str, sizeof(nexthop_str)));
if (nexthop.mrib_nexthop_addr.family == AF_INET)
nh_addr = nexthop.mrib_nexthop_addr.u.prefix4;
}
/* 6.4 Forwarding Traceroute Requests: ... Otherwise, ... */
else {
if (PIM_DEBUG_MTRACE)
zlog_debug("mtrace not found neighbor");
if (!fwd_code)
rspp->fwd_code = MTRACE_FWD_CODE_NO_ROUTE;
else
rspp->fwd_code = fwd_code;
/* 6.5 Sending Traceroute Responses */
zlog_debug("mtrace not found multicast state");
mtrace_rsp_set_fwd_code(rspp, MTRACE_FWD_CODE_NO_ROUTE);
/* 6.2.2. 3. forward the packet to requester */
return mtrace_send_response(pim, mtracep, mtrace_len);
}
out_ifp = nexthop.interface;
nh_addr = rspp->prev_hop;
rspp->incoming = mtrace_primary_address(out_ifp);
rspp->prev_hop = nh_addr;
rspp->in_count = htonl(MTRACE_UNKNOWN_COUNT);
rspp->total = htonl(MTRACE_UNKNOWN_COUNT);
rspp->rtg_proto = MTRACE_RTG_PROTO_PIM;
rspp->fwd_ttl = 1;
rspp->s = 1;
rspp->src_mask = 32;
reached_source = false;
if (nh_addr.s_addr == 0) {
/* no pim? */
/* no pim? i.e. 7.5.3. No Previous Hop */
if (!out_ifp->info) {
rspp->fwd_code = MTRACE_FWD_CODE_NO_MULTICAST;
if (PIM_DEBUG_MTRACE)
zlog_debug("mtrace not found incoming if w/ pim");
mtrace_rsp_set_fwd_code(rspp,
MTRACE_FWD_CODE_NO_MULTICAST);
return mtrace_send_response(pim, mtracep, mtrace_len);
}
/* reached source? */
/* reached source? i.e. 7.5.1 Arriving at source */
if (pim_if_connected_to_source(out_ifp, mtracep->src_addr)) {
reached_source = true;
rspp->prev_hop = mtracep->src_addr;
return mtrace_send_response(pim, mtracep, mtrace_len);
}
/*
* 6.4 Forwarding Traceroute Requests:
* Previous-hop router not known
* Previous-hop router not known,
* packet is sent to an appropriate multicast address
*/
inet_aton(MCAST_ALL_ROUTERS, &nh_addr);
}
/* 6.2.2 8. If this router is the Rendez-vous Point */
if (pim_rp_i_am_rp(pim, mtracep->grp_addr)) {
mtrace_rsp_set_fwd_code(rspp, MTRACE_FWD_CODE_REACHED_RP);
/* 7.7.1. PIM-SM ...RP has not performed source-specific join */
if (rspp->src_mask == MTRACE_SRC_MASK_GROUP)
return mtrace_send_response(pim, mtracep, mtrace_len);
}
/*
* 6.4 Forwarding Traceroute Requests: the number of response
* blocks exceeds number of responses, so forward to the requester.
*/
if (mtracep->hops <= (last_rsp_ind + 1))
return mtrace_send_response(pim, mtracep, mtrace_len);
/* 7.5.1. Arriving at source: terminate trace */
if (reached_source)
return mtrace_send_response(pim, mtracep, mtrace_len);
mtracep->checksum = 0;
mtracep->checksum = in_cksum(mtrace_buf, mtrace_len);
/* 6.4 Forwarding Traceroute Requests: response blocks less than req. */
return mtrace_send_packet(out_ifp, mtracep, mtrace_len, nh_addr,
mtracep->grp_addr);
}
/* 6.3. Traceroute responses */
int igmp_mtrace_recv_response(struct igmp_sock *igmp, struct ip *ip_hdr,
struct in_addr from, const char *from_str,
char *igmp_msg, int igmp_msg_len)

View File

@ -26,6 +26,8 @@
#define MTRACE_MAX_HOPS (255)
#define MTRACE_UNKNOWN_COUNT (0xffffffff)
#define MTRACE_SRC_MASK_GROUP (0x3f) /* forwarding on group state (*,G) */
#define MTRACE_SRC_MASK_SOURCE (0x20) /* i.e. 32 forwarding on (S,G) */
enum mtrace_fwd_code {
MTRACE_FWD_CODE_NO_ERROR = 0x00,

View File

@ -2792,14 +2792,15 @@ ALIAS(vtysh_traceroute, vtysh_traceroute_ip_cmd, "traceroute ip WORD",
DEFUN (vtysh_mtrace,
vtysh_mtrace_cmd,
"mtrace WORD",
"mtrace WORD [WORD]",
"Multicast trace route to multicast source\n"
"Multicast trace route to multicast source address\n")
"Multicast trace route to multicast source address\n"
"Multicast trace route for multicast group address\n")
{
int idx = 1;
argv_find(argv, argc, "WORD", &idx);
execute_command("mtracebis", 1, argv[idx]->arg, NULL);
if (argc == 2)
execute_command("mtracebis", 1, argv[1]->arg, NULL);
else
execute_command("mtracebis", 2, argv[1]->arg, argv[2]->arg);
return CMD_SUCCESS;
}