Merge pull request #42 from donaldsharp/pim_lib_work2

Pim-SM + MSDP
This commit is contained in:
David Lamparter 2017-01-24 17:10:09 +01:00 committed by GitHub
commit e5951aa21d
87 changed files with 13110 additions and 5130 deletions

View File

@ -1849,7 +1849,8 @@ int
bgp_mp_reach_parse (struct bgp_attr_parser_args *args, bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
struct bgp_nlri *mp_update) struct bgp_nlri *mp_update)
{ {
afi_t pkt_afi, afi; iana_afi_t pkt_afi;
afi_t afi;
safi_t pkt_safi, safi; safi_t pkt_safi, safi;
bgp_size_t nlri_len; bgp_size_t nlri_len;
size_t start; size_t start;
@ -2000,7 +2001,8 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
struct bgp_nlri *mp_withdraw) struct bgp_nlri *mp_withdraw)
{ {
struct stream *s; struct stream *s;
afi_t pkt_afi, afi; iana_afi_t pkt_afi;
afi_t afi;
safi_t pkt_safi, safi; safi_t pkt_safi, safi;
u_int16_t withdraw_len; u_int16_t withdraw_len;
struct peer *const peer = args->peer; struct peer *const peer = args->peer;
@ -2648,7 +2650,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi,
struct attr *attr) struct attr *attr)
{ {
size_t sizep; size_t sizep;
afi_t pkt_afi; iana_afi_t pkt_afi;
safi_t pkt_safi; safi_t pkt_safi;
/* Set extended bit always to encode the attribute length as 2 bytes */ /* Set extended bit always to encode the attribute length as 2 bytes */
@ -3282,7 +3284,7 @@ size_t
bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi) bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi)
{ {
unsigned long attrlen_pnt; unsigned long attrlen_pnt;
afi_t pkt_afi; iana_afi_t pkt_afi;
safi_t pkt_safi; safi_t pkt_safi;
/* Set extended bit always to encode the attribute length as 2 bytes */ /* Set extended bit always to encode the attribute length as 2 bytes */

View File

@ -188,7 +188,9 @@ bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
{ {
struct capability_mp_data mpc; struct capability_mp_data mpc;
struct stream *s = BGP_INPUT (peer); struct stream *s = BGP_INPUT (peer);
afi_t afi;
safi_t safi;
/* Verify length is 4 */ /* Verify length is 4 */
if (hdr->length != 4) if (hdr->length != 4)
{ {
@ -204,14 +206,14 @@ bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
peer->host, mpc.afi, mpc.safi); peer->host, mpc.afi, mpc.safi);
/* Convert AFI, SAFI to internal values, check. */ /* Convert AFI, SAFI to internal values, check. */
if (bgp_map_afi_safi_iana2int (mpc.afi, mpc.safi, &mpc.afi, &mpc.safi)) if (bgp_map_afi_safi_iana2int (mpc.afi, mpc.safi, &afi, &safi))
return -1; return -1;
/* Now safi remapped, and afi/safi are valid array indices */ /* Now safi remapped, and afi/safi are valid array indices */
peer->afc_recv[mpc.afi][mpc.safi] = 1; peer->afc_recv[afi][safi] = 1;
if (peer->afc[mpc.afi][mpc.safi]) if (peer->afc[afi][safi])
peer->afc_nego[mpc.afi][mpc.safi] = 1; peer->afc_nego[afi][safi] = 1;
else else
return -1; return -1;
@ -219,7 +221,7 @@ bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
} }
static void static void
bgp_capability_orf_not_support (struct peer *peer, afi_t afi, safi_t safi, bgp_capability_orf_not_support (struct peer *peer, iana_afi_t afi, safi_t safi,
u_char type, u_char mode) u_char type, u_char mode)
{ {
if (bgp_debug_neighbor_events(peer)) if (bgp_debug_neighbor_events(peer))
@ -247,7 +249,8 @@ bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)
{ {
struct stream *s = BGP_INPUT (peer); struct stream *s = BGP_INPUT (peer);
struct capability_orf_entry entry; struct capability_orf_entry entry;
afi_t pkt_afi, afi; iana_afi_t pkt_afi;
afi_t afi;
safi_t pkt_safi, safi; safi_t pkt_safi, safi;
u_char type; u_char type;
u_char mode; u_char mode;
@ -274,7 +277,7 @@ bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)
return 0; return 0;
} }
entry.mpc.afi = afi; entry.mpc.afi = pkt_afi;
entry.mpc.safi = safi; entry.mpc.safi = safi;
/* validate number field */ /* validate number field */
@ -418,7 +421,7 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)
{ {
afi_t afi; afi_t afi;
safi_t safi; safi_t safi;
afi_t pkt_afi = stream_getw (s); iana_afi_t pkt_afi = stream_getw (s);
safi_t pkt_safi = stream_getc (s); safi_t pkt_safi = stream_getc (s);
u_char flag = stream_getc (s); u_char flag = stream_getc (s);
@ -496,7 +499,7 @@ bgp_capability_addpath (struct peer *peer, struct capability_header *hdr)
{ {
afi_t afi; afi_t afi;
safi_t safi; safi_t safi;
afi_t pkt_afi = stream_getw (s); iana_afi_t pkt_afi = stream_getw (s);
safi_t pkt_safi = stream_getc (s); safi_t pkt_safi = stream_getc (s);
u_char send_receive = stream_getc (s); u_char send_receive = stream_getc (s);
@ -550,9 +553,11 @@ bgp_capability_enhe (struct peer *peer, struct capability_header *hdr)
while (stream_get_getp (s) + 6 <= end) while (stream_get_getp (s) + 6 <= end)
{ {
afi_t afi, pkt_afi = stream_getw (s); iana_afi_t pkt_afi = stream_getw (s);
afi_t afi;
safi_t safi, pkt_safi = stream_getw (s); safi_t safi, pkt_safi = stream_getw (s);
afi_t nh_afi, pkt_nh_afi = stream_getw (s); iana_afi_t pkt_nh_afi = stream_getw (s);
afi_t nh_afi;
if (bgp_debug_neighbor_events(peer)) if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s Received with afi/safi/next-hop afi: %u/%u/%u", zlog_debug ("%s Received with afi/safi/next-hop afi: %u/%u/%u",
@ -1162,7 +1167,7 @@ bgp_open_capability_orf (struct stream *s, struct peer *peer,
unsigned long orfp; unsigned long orfp;
unsigned long numberp; unsigned long numberp;
int number_of_orfs = 0; int number_of_orfs = 0;
afi_t pkt_afi; iana_afi_t pkt_afi;
safi_t pkt_safi; safi_t pkt_safi;
/* Convert AFI, SAFI to values for packet. */ /* Convert AFI, SAFI to values for packet. */
@ -1225,7 +1230,8 @@ bgp_open_capability (struct stream *s, struct peer *peer)
{ {
u_char len; u_char len;
unsigned long cp, capp, rcapp; unsigned long cp, capp, rcapp;
afi_t afi, pkt_afi; iana_afi_t pkt_afi;
afi_t afi;
safi_t safi, pkt_safi; safi_t safi, pkt_safi;
as_t local_as; as_t local_as;
u_int32_t restart_time; u_int32_t restart_time;

View File

@ -31,7 +31,7 @@ struct capability_header
/* Generic MP capability data */ /* Generic MP capability data */
struct capability_mp_data struct capability_mp_data
{ {
afi_t afi; iana_afi_t afi;
u_char reserved; u_char reserved;
safi_t safi; safi_t safi;
}; };

View File

@ -147,7 +147,7 @@ static struct stream *
bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi) bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi)
{ {
struct stream *s; struct stream *s;
afi_t pkt_afi; iana_afi_t pkt_afi;
safi_t pkt_safi; safi_t pkt_safi;
if (DISABLE_BGP_ANNOUNCE) if (DISABLE_BGP_ANNOUNCE)
@ -695,7 +695,7 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi,
struct stream *s; struct stream *s;
struct bgp_filter *filter; struct bgp_filter *filter;
int orf_refresh = 0; int orf_refresh = 0;
afi_t pkt_afi; iana_afi_t pkt_afi;
safi_t pkt_safi; safi_t pkt_safi;
if (DISABLE_BGP_ANNOUNCE) if (DISABLE_BGP_ANNOUNCE)
@ -782,7 +782,7 @@ bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi,
int capability_code, int action) int capability_code, int action)
{ {
struct stream *s; struct stream *s;
afi_t pkt_afi; iana_afi_t pkt_afi;
safi_t pkt_safi; safi_t pkt_safi;
/* Convert AFI, SAFI to values for packet. */ /* Convert AFI, SAFI to values for packet. */
@ -1711,7 +1711,8 @@ bgp_keepalive_receive (struct peer *peer, bgp_size_t size)
static void static void
bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
{ {
afi_t pkt_afi, afi; iana_afi_t pkt_afi;
afi_t afi;
safi_t pkt_safi, safi; safi_t pkt_safi, safi;
struct stream *s; struct stream *s;
struct peer_af *paf; struct peer_af *paf;
@ -1932,7 +1933,8 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
struct capability_mp_data mpc; struct capability_mp_data mpc;
struct capability_header *hdr; struct capability_header *hdr;
u_char action; u_char action;
afi_t pkt_afi, afi; iana_afi_t pkt_afi;
afi_t afi;
safi_t pkt_safi, safi; safi_t pkt_safi, safi;
end = pnt + length; end = pnt + length;

View File

@ -2111,10 +2111,10 @@ bgp_maximum_prefix_restart_timer (struct thread *thread)
} }
int int
bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi, bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
safi_t safi, int always) safi_t safi, int always)
{ {
afi_t pkt_afi; iana_afi_t pkt_afi;
safi_t pkt_safi; safi_t pkt_safi;
if (!CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) if (!CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX))

View File

@ -652,7 +652,7 @@ bgp_listen_limit_unset (struct bgp *bgp)
} }
int int
bgp_map_afi_safi_iana2int (afi_t pkt_afi, safi_t pkt_safi, bgp_map_afi_safi_iana2int (iana_afi_t pkt_afi, safi_t pkt_safi,
afi_t *afi, safi_t *safi) afi_t *afi, safi_t *safi)
{ {
/* Map from IANA values to internal values, return error if /* Map from IANA values to internal values, return error if
@ -668,7 +668,7 @@ bgp_map_afi_safi_iana2int (afi_t pkt_afi, safi_t pkt_safi,
int int
bgp_map_afi_safi_int2iana (afi_t afi, safi_t safi, bgp_map_afi_safi_int2iana (afi_t afi, safi_t safi,
afi_t *pkt_afi, safi_t *pkt_safi) iana_afi_t *pkt_afi, safi_t *pkt_safi)
{ {
/* Map from internal values to IANA values, return error if /* Map from internal values to IANA values, return error if
* internal values are bad (unexpected). * internal values are bad (unexpected).

View File

@ -1355,11 +1355,11 @@ extern void bgp_route_map_terminate(void);
extern int peer_cmp (struct peer *p1, struct peer *p2); extern int peer_cmp (struct peer *p1, struct peer *p2);
extern int extern int
bgp_map_afi_safi_iana2int (afi_t pkt_afi, safi_t pkt_safi, bgp_map_afi_safi_iana2int (iana_afi_t pkt_afi, safi_t pkt_safi,
afi_t *afi, safi_t *safi); afi_t *afi, safi_t *safi);
extern int extern int
bgp_map_afi_safi_int2iana (afi_t afi, safi_t safi, bgp_map_afi_safi_int2iana (afi_t afi, safi_t safi,
afi_t *pkt_afi, safi_t *pkt_safi); iana_afi_t *pkt_afi, safi_t *pkt_safi);
extern struct peer_af * peer_af_create (struct peer *, afi_t, safi_t); extern struct peer_af * peer_af_create (struct peer *, afi_t, safi_t);
extern struct peer_af * peer_af_find (struct peer *, afi_t, safi_t); extern struct peer_af * peer_af_find (struct peer *, afi_t, safi_t);

View File

@ -989,6 +989,7 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY (ZEBRA_IPV4_NEXTHOP_DELETE), DESC_ENTRY (ZEBRA_IPV4_NEXTHOP_DELETE),
DESC_ENTRY (ZEBRA_IPV6_NEXTHOP_ADD), DESC_ENTRY (ZEBRA_IPV6_NEXTHOP_ADD),
DESC_ENTRY (ZEBRA_IPV6_NEXTHOP_DELETE), DESC_ENTRY (ZEBRA_IPV6_NEXTHOP_DELETE),
DESC_ENTRY (ZEBRA_IPMR_ROUTE_STATS),
}; };
#undef DESC_ENTRY #undef DESC_ENTRY

View File

@ -62,8 +62,13 @@ writen(int fd, const u_char *ptr, int nbytes)
while (nleft > 0) while (nleft > 0)
{ {
nwritten = write(fd, ptr, nleft); nwritten = write(fd, ptr, nleft);
if (nwritten <= 0) if (nwritten < 0)
{
if (!ERRNO_IO_RETRY(errno))
return nwritten;
}
if (nwritten == 0)
return (nwritten); return (nwritten);
nleft -= nwritten; nleft -= nwritten;

View File

@ -405,6 +405,7 @@ typedef enum {
ZEBRA_IPV4_NEXTHOP_DELETE, ZEBRA_IPV4_NEXTHOP_DELETE,
ZEBRA_IPV6_NEXTHOP_ADD, ZEBRA_IPV6_NEXTHOP_ADD,
ZEBRA_IPV6_NEXTHOP_DELETE, ZEBRA_IPV6_NEXTHOP_DELETE,
ZEBRA_IPMR_ROUTE_STATS,
} zebra_message_types_t; } zebra_message_types_t;
/* Marker value used in new Zserv, in the byte location corresponding /* Marker value used in new Zserv, in the byte location corresponding
@ -477,6 +478,12 @@ typedef enum {
#define SAFI_RESERVED_5 5 #define SAFI_RESERVED_5 5
#define SAFI_MAX 6 #define SAFI_MAX 6
#define IANA_SAFI_RESERVED 0
#define IANA_SAFI_UNICAST 1
#define IANA_SAFI_MULTICAST 2
#define IANA_SAFI_ENCAP 7
#define IANA_SAFI_MPLS_VPN 128
/* /*
* The above AFI and SAFI definitions are for internal use. The protocol * The above AFI and SAFI definitions are for internal use. The protocol
* definitions (IANA values) as for example used in BGP protocol packets * definitions (IANA values) as for example used in BGP protocol packets
@ -486,12 +493,14 @@ typedef enum {
* not optimal for use in data-structure sizing. * not optimal for use in data-structure sizing.
* Note: Only useful (i.e., supported) values are defined below. * Note: Only useful (i.e., supported) values are defined below.
*/ */
#define IANA_AFI_RESERVED 0 typedef enum {
#define IANA_AFI_IPV4 1 IANA_AFI_RESERVED = 0,
#define IANA_AFI_IPV6 2 IANA_AFI_IPV4 = 1,
#define IANA_AFI_L2VPN 25 IANA_AFI_IPV6 = 2,
#define IANA_AFI_IPMR 128 IANA_AFI_L2VPN = 25,
#define IANA_AFI_IP6MR 129 IANA_AFI_IPMR = 128,
IANA_AFI_IP6MR = 129
} iana_afi_t;
#define IANA_SAFI_RESERVED 0 #define IANA_SAFI_RESERVED 0
#define IANA_SAFI_UNICAST 1 #define IANA_SAFI_UNICAST 1
@ -531,7 +540,7 @@ typedef uint32_t route_tag_t;
#define ROUTE_TAG_MAX UINT32_MAX #define ROUTE_TAG_MAX UINT32_MAX
#define ROUTE_TAG_PRI PRIu32 #define ROUTE_TAG_PRI PRIu32
static inline afi_t afi_iana2int (afi_t afi) static inline afi_t afi_iana2int (iana_afi_t afi)
{ {
if (afi == IANA_AFI_IPV4) if (afi == IANA_AFI_IPV4)
return AFI_IP; return AFI_IP;
@ -540,7 +549,7 @@ static inline afi_t afi_iana2int (afi_t afi)
return AFI_MAX; return AFI_MAX;
} }
static inline afi_t afi_int2iana (afi_t afi) static inline iana_afi_t afi_int2iana (afi_t afi)
{ {
if (afi == AFI_IP) if (afi == AFI_IP)
return IANA_AFI_IPV4; return IANA_AFI_IPV4;

View File

@ -19,7 +19,6 @@
# 330, Boston, MA 02111-1307, USA. # 330, Boston, MA 02111-1307, USA.
# PIM_DEBUG_BYDEFAULT: Automatically enables all pimd "debug ..." commands # PIM_DEBUG_BYDEFAULT: Automatically enables all pimd "debug ..." commands
# PIM_ZCLIENT_DEBUG: Support for internal ZEBRA client debugging
# PIM_CHECK_RECV_IFINDEX_SANITY: Compare socket ifindex with recv ifindex # PIM_CHECK_RECV_IFINDEX_SANITY: Compare socket ifindex with recv ifindex
# PIM_REPORT_RECV_IFINDEX_MISMATCH: Report sock/recv ifindex mismatch # PIM_REPORT_RECV_IFINDEX_MISMATCH: Report sock/recv ifindex mismatch
# PIM_ENFORCE_LOOPFREE_MFC: Refuse adding looping MFC entries # PIM_ENFORCE_LOOPFREE_MFC: Refuse adding looping MFC entries
@ -27,9 +26,8 @@
PIM_DEFS = PIM_DEFS =
#PIM_DEFS += -DPIM_DEBUG_BYDEFAULT #PIM_DEFS += -DPIM_DEBUG_BYDEFAULT
PIM_DEFS += -DPIM_CHECK_RECV_IFINDEX_SANITY #PIM_DEFS += -DPIM_CHECK_RECV_IFINDEX_SANITY
#PIM_DEFS += -DPIM_REPORT_RECV_IFINDEX_MISMATCH #PIM_DEFS += -DPIM_REPORT_RECV_IFINDEX_MISMATCH
PIM_DEFS += -DPIM_ZCLIENT_DEBUG
PIM_DEFS += -DPIM_ENFORCE_LOOPFREE_MFC PIM_DEFS += -DPIM_ENFORCE_LOOPFREE_MFC
#PIM_DEFS += -DPIM_UNEXPECTED_KERNEL_UPCALL #PIM_DEFS += -DPIM_UNEXPECTED_KERNEL_UPCALL
@ -47,24 +45,26 @@ noinst_PROGRAMS = test_igmpv3_join
libpim_a_SOURCES = \ libpim_a_SOURCES = \
pim_memory.c \ pim_memory.c \
pimd.c pim_version.c pim_cmd.c pim_signals.c pim_iface.c \ pimd.c pim_version.c pim_cmd.c pim_signals.c pim_iface.c \
pim_vty.c pim_igmp.c pim_sock.c pim_zebra.c \ pim_vty.c pim_igmp.c pim_sock.c pim_zebra.c pim_igmpv2.c \
pim_igmpv3.c pim_str.c pim_mroute.c pim_util.c pim_time.c \ pim_igmpv3.c pim_str.c pim_mroute.c pim_util.c pim_time.c \
pim_oil.c pim_zlookup.c pim_pim.c pim_tlv.c pim_neighbor.c \ pim_oil.c pim_zlookup.c pim_pim.c pim_tlv.c pim_neighbor.c \
pim_hello.c pim_ifchannel.c pim_join.c pim_assert.c \ pim_hello.c pim_ifchannel.c pim_join.c pim_assert.c \
pim_msg.c pim_upstream.c pim_rpf.c pim_macro.c \ pim_msg.c pim_upstream.c pim_rpf.c pim_macro.c \
pim_ssmpingd.c pim_int.c pim_rp.c \ pim_ssmpingd.c pim_int.c pim_rp.c \
pim_static.c pim_br.c pim_register.c pim_routemap.c pim_static.c pim_br.c pim_register.c pim_routemap.c \
pim_msdp.c pim_msdp_socket.c pim_msdp_packet.c
noinst_HEADERS = \ noinst_HEADERS = \
pim_memory.h \ pim_memory.h \
pimd.h pim_version.h pim_cmd.h pim_signals.h pim_iface.h \ pimd.h pim_version.h pim_cmd.h pim_signals.h pim_iface.h \
pim_vty.h pim_igmp.h pim_sock.h pim_zebra.h \ pim_vty.h pim_igmp.h pim_sock.h pim_zebra.h pim_igmpv2.h \
pim_igmpv3.h pim_str.h pim_mroute.h pim_util.h pim_time.h \ pim_igmpv3.h pim_str.h pim_mroute.h pim_util.h pim_time.h \
pim_oil.h pim_zlookup.h pim_pim.h pim_tlv.h pim_neighbor.h \ pim_oil.h pim_zlookup.h pim_pim.h pim_tlv.h pim_neighbor.h \
pim_hello.h pim_ifchannel.h pim_join.h pim_assert.h \ pim_hello.h pim_ifchannel.h pim_join.h pim_assert.h \
pim_msg.h pim_upstream.h pim_rpf.h pim_macro.h \ pim_msg.h pim_upstream.h pim_rpf.h pim_macro.h \
pim_igmp_join.h pim_ssmpingd.h pim_int.h pim_rp.h \ pim_igmp_join.h pim_ssmpingd.h pim_int.h pim_rp.h \
pim_static.h pim_br.h pim_register.h pim_static.h pim_br.h pim_register.h \
pim_msdp.h pim_msdp_socket.h pim_msdp_packet.h
pimd_SOURCES = \ pimd_SOURCES = \
pim_main.c $(libpim_a_SOURCES) pim_main.c $(libpim_a_SOURCES)

View File

@ -1,18 +1,17 @@
INTRODUCTION INTRODUCTION
qpimd aims to implement a PIM (Protocol Independent Multicast) qpimd aims to implement a PIM (Protocol Independent Multicast)
daemon for the Quagga Routing Suite. daemon for the FRR Routing Suite.
Initially qpimd targets only PIM SSM (Source-Specific qpimd implements PIM-SM (Sparse Mode) of RFC 4601.
Multicast) mode as defined in section 4.8.2 (PIM-SSM-Only Additionally MSDP has been implemented.
Routers) of RFC 4601.
In order to deliver end-to-end multicast routing control In order to deliver end-to-end multicast routing control
plane, qpimd includes the router-side of IGMPv3 (RFC 3376). plane, qpimd includes the router-side of IGMPv[2|3] (RFC 3376).
LICENSE LICENSE
qpimd - pimd for quagga qpimd - pimd for FRR
Copyright (C) 2008 Everton da Silva Marques Copyright (C) 2008 Everton da Silva Marques
qpimd is free software; you can redistribute it and/or modify qpimd is free software; you can redistribute it and/or modify
@ -34,78 +33,16 @@ HOME SITE
qpimd lives at: qpimd lives at:
https://github.com/udhos/qpimd https://github.com/freerangerouting/frr
PLATFORMS PLATFORMS
qpimd has been tested with Debian Lenny under Linux 2.6. qpimd has been tested with Debian Jessie.
REQUIREMENTS REQUIREMENTS
qpimd requires Quagga (0.99.11 or higher from http://www.quagga.net) qpimd requires FRR (2.0 or higher)
The GNU Build System (Autotools) is required to build from
source code repository.
gawk is also needed to build with Autotools. Any other awk
usually won't work.
BUILDING FROM QUAGGA GIT REPOSITORY
1) Get the latest quagga source tree
# git clone git://code.quagga.net/quagga.git quagga
2) Apply qpimd patch into quagga source tree
# patch -p1 -d quagga < pimd-0.153-quagga-git20090623.patch
3) Compile and install quagga
# cd quagga
# ./bootstrap.sh
# ./configure --prefix=/usr/local/quagga --enable-pimd
# make
# make install
BUILDING FROM QUAGGA TARBALL
1) Get the latest quagga tarball
# wget http://www.quagga.net/download/quagga-0.99.13.tar.gz
2) Unpack the quagga tarball
# tar xzf quagga-0.99.13.tar.gz
3) Apply qpimd patch into quagga source tree
# patch -p1 -d quagga-0.99.13 < pimd-0.153-quagga-0.99.13.patch
4) Compile and install quagga
# cd quagga-0.99.13
# ./configure --prefix=/usr/local/quagga --enable-pimd
# make
# make install
USAGE
1) Configure and start the zebra daemon
# cp /usr/local/quagga/etc/zebra.conf.sample /usr/local/quagga/etc/zebra.conf
# vi /usr/local/quagga/etc/zebra.conf
# /usr/local/quagga/sbin/zebra
2) Configure and start the pimd daemon
# cp /usr/local/quagga/etc/pimd.conf.sample /usr/local/quagga/etc/pimd.conf
# vi /usr/local/quagga/etc/pimd.conf
# /usr/local/quagga/sbin/pimd
3) Access pimd vty interface at port TCP 2611
# telnet localhost 2611
CONFIGURATION COMMANDS CONFIGURATION COMMANDS
@ -120,7 +57,7 @@ SUPPORT
Please post comments, questions, patches, bug reports at the Please post comments, questions, patches, bug reports at the
support site: support site:
https://github.com/udhos/qpimd https://freerangerouting/frr
RELATED WORK RELATED WORK

View File

@ -54,31 +54,23 @@ void pim_ifassert_winner_set(struct pim_ifchannel *ch,
if (PIM_DEBUG_PIM_EVENTS) { if (PIM_DEBUG_PIM_EVENTS) {
if (ch->ifassert_state != new_state) { if (ch->ifassert_state != new_state) {
char src_str[100]; zlog_debug("%s: (S,G)=%s assert state changed from %s to %s on interface %s",
char grp_str[100]; __PRETTY_FUNCTION__,
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str)); ch->sg_str,
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str)); pim_ifchannel_ifassert_name(ch->ifassert_state),
zlog_debug("%s: (S,G)=(%s,%s) assert state changed from %s to %s on interface %s", pim_ifchannel_ifassert_name(new_state),
__PRETTY_FUNCTION__, ch->interface->name);
src_str, grp_str,
pim_ifchannel_ifassert_name(ch->ifassert_state),
pim_ifchannel_ifassert_name(new_state),
ch->interface->name);
} }
if (winner_changed) { if (winner_changed) {
char src_str[100]; char was_str[INET_ADDRSTRLEN];
char grp_str[100]; char winner_str[INET_ADDRSTRLEN];
char was_str[100];
char winner_str[100];
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
pim_inet4_dump("<was?>", ch->ifassert_winner, was_str, sizeof(was_str)); pim_inet4_dump("<was?>", ch->ifassert_winner, was_str, sizeof(was_str));
pim_inet4_dump("<winner?>", winner, winner_str, sizeof(winner_str)); pim_inet4_dump("<winner?>", winner, winner_str, sizeof(winner_str));
zlog_debug("%s: (S,G)=(%s,%s) assert winner changed from %s to %s on interface %s", zlog_debug("%s: (S,G)=%s assert winner changed from %s to %s on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str, ch->sg_str,
was_str, winner_str, ch->interface->name); was_str, winner_str, ch->interface->name);
} }
} /* PIM_DEBUG_PIM_EVENTS */ } /* PIM_DEBUG_PIM_EVENTS */
@ -98,7 +90,7 @@ static void on_trace(const char *label,
struct interface *ifp, struct in_addr src) struct interface *ifp, struct in_addr src)
{ {
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_TRACE) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
zlog_debug("%s: from %s on %s", zlog_debug("%s: from %s on %s",
label, src_str, ifp->name); label, src_str, ifp->name);
@ -138,13 +130,9 @@ static void if_could_assert_do_a1(const char *caller,
{ {
if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) { if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
if (assert_action_a1(ch)) { if (assert_action_a1(ch)) {
char src_str[100]; zlog_warn("%s: %s: (S,G)=%s assert_action_a1 failure on interface %s",
char grp_str[100];
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
zlog_warn("%s: %s: (S,G)=(%s,%s) assert_action_a1 failure on interface %s",
__PRETTY_FUNCTION__, caller, __PRETTY_FUNCTION__, caller,
src_str, grp_str, ch->interface->name); ch->sg_str, ch->interface->name);
/* log warning only */ /* log warning only */
} }
} }
@ -156,16 +144,16 @@ static int dispatch_assert(struct interface *ifp,
struct pim_assert_metric recv_metric) struct pim_assert_metric recv_metric)
{ {
struct pim_ifchannel *ch; struct pim_ifchannel *ch;
struct prefix_sg sg;
ch = pim_ifchannel_add(ifp, source_addr, group_addr); memset (&sg, 0, sizeof (struct prefix_sg));
sg.src = source_addr;
sg.grp = group_addr;
ch = pim_ifchannel_add(ifp, &sg, 0);
if (!ch) { if (!ch) {
char source_str[100]; zlog_warn("%s: (S,G)=%s failure creating channel on interface %s",
char group_str[100];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
zlog_warn("%s: (S,G)=(%s,%s) failure creating channel on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
source_str, group_str, ifp->name); pim_str_sg_dump (&sg), ifp->name);
return -1; return -1;
} }
@ -193,7 +181,6 @@ static int dispatch_assert(struct interface *ifp,
} }
else { else {
if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) { if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
assert_action_a3(ch); assert_action_a3(ch);
} }
} }
@ -222,13 +209,9 @@ static int dispatch_assert(struct interface *ifp,
break; break;
default: default:
{ {
char source_str[100]; zlog_warn("%s: (S,G)=%s invalid assert state %d on interface %s",
char group_str[100];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
source_str, group_str, ch->ifassert_state, ifp->name); ch->sg_str, ch->ifassert_state, ifp->name);
} }
return -2; return -2;
} }
@ -241,7 +224,7 @@ int pim_assert_recv(struct interface *ifp,
struct in_addr src_addr, struct in_addr src_addr,
uint8_t *buf, int buf_size) uint8_t *buf, int buf_size)
{ {
struct prefix msg_group_addr; struct prefix_sg sg;
struct prefix msg_source_addr; struct prefix msg_source_addr;
struct pim_assert_metric msg_metric; struct pim_assert_metric msg_metric;
int offset; int offset;
@ -256,9 +239,10 @@ int pim_assert_recv(struct interface *ifp,
/* /*
Parse assert group addr Parse assert group addr
*/ */
offset = pim_parse_addr_group (&msg_group_addr, curr, curr_size); memset (&sg, 0, sizeof (struct prefix_sg));
offset = pim_parse_addr_group (&sg, curr, curr_size);
if (offset < 1) { if (offset < 1) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s", zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -273,7 +257,7 @@ int pim_assert_recv(struct interface *ifp,
*/ */
offset = pim_parse_addr_ucast (&msg_source_addr, curr, curr_size); offset = pim_parse_addr_ucast (&msg_source_addr, curr, curr_size);
if (offset < 1) { if (offset < 1) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -284,7 +268,7 @@ int pim_assert_recv(struct interface *ifp,
curr_size -= offset; curr_size -= offset;
if (curr_size != 8) { if (curr_size != 8) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: preference/metric size is not 8: size=%d from %s on interface %s", zlog_warn("%s: preference/metric size is not 8: size=%d from %s on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -311,12 +295,12 @@ int pim_assert_recv(struct interface *ifp,
msg_metric.route_metric = pim_read_uint32_host(curr); msg_metric.route_metric = pim_read_uint32_host(curr);
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_TRACE) {
char neigh_str[100]; char neigh_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
char group_str[100]; char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<neigh?>", src_addr, neigh_str, sizeof(neigh_str)); pim_inet4_dump("<neigh?>", src_addr, neigh_str, sizeof(neigh_str));
pim_inet4_dump("<src?>", msg_source_addr.u.prefix4, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", msg_source_addr.u.prefix4, source_str, sizeof(source_str));
pim_inet4_dump("<grp?>", msg_group_addr.u.prefix4, group_str, sizeof(group_str)); pim_inet4_dump("<grp?>", sg.grp, group_str, sizeof(group_str));
zlog_debug("%s: from %s on %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u", zlog_debug("%s: from %s on %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
__PRETTY_FUNCTION__, neigh_str, ifp->name, __PRETTY_FUNCTION__, neigh_str, ifp->name,
source_str, group_str, source_str, group_str,
@ -329,7 +313,7 @@ int pim_assert_recv(struct interface *ifp,
return dispatch_assert(ifp, return dispatch_assert(ifp,
msg_source_addr.u.prefix4, msg_source_addr.u.prefix4,
msg_group_addr.u.prefix4, sg.grp,
msg_metric); msg_metric);
} }
@ -399,7 +383,7 @@ int pim_assert_build_msg(uint8_t *pim_msg, int buf_size,
remain, remain,
group_addr); group_addr);
if (!pim_msg_curr) { if (!pim_msg_curr) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
zlog_warn("%s: failure encoding group address %s: space left=%d", zlog_warn("%s: failure encoding group address %s: space left=%d",
__PRETTY_FUNCTION__, group_str, remain); __PRETTY_FUNCTION__, group_str, remain);
@ -412,7 +396,7 @@ int pim_assert_build_msg(uint8_t *pim_msg, int buf_size,
remain, remain,
source_addr); source_addr);
if (!pim_msg_curr) { if (!pim_msg_curr) {
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: failure encoding source address %s: space left=%d", zlog_warn("%s: failure encoding source address %s: space left=%d",
__PRETTY_FUNCTION__, source_str, remain); __PRETTY_FUNCTION__, source_str, remain);
@ -448,17 +432,23 @@ static int pim_assert_do(struct pim_ifchannel *ch,
int pim_msg_size; int pim_msg_size;
ifp = ch->interface; ifp = ch->interface;
zassert(ifp); if (!ifp)
{
if (PIM_DEBUG_PIM_TRACE)
zlog_debug("%s: channel%s has no associated interface!",
__PRETTY_FUNCTION__, ch->sg_str);
return -1;
}
pim_ifp = ifp->info; pim_ifp = ifp->info;
if (!pim_ifp) { if (!pim_ifp) {
zlog_warn("%s: pim not enabled on interface: %s", if (PIM_DEBUG_PIM_TRACE)
__PRETTY_FUNCTION__, ifp->name); zlog_debug("%s: channel %s pim not enabled on interface: %s",
__PRETTY_FUNCTION__, ch->sg_str, ifp->name);
return -1; return -1;
} }
pim_msg_size = pim_assert_build_msg(pim_msg, sizeof(pim_msg), ifp, pim_msg_size = pim_assert_build_msg(pim_msg, sizeof(pim_msg), ifp,
ch->group_addr, ch->source_addr, ch->sg.grp, ch->sg.src,
metric.metric_preference, metric.metric_preference,
metric.route_metric, metric.route_metric,
metric.rpt_bit_flag); metric.rpt_bit_flag);
@ -480,19 +470,16 @@ static int pim_assert_do(struct pim_ifchannel *ch,
pim_hello_require(ifp); pim_hello_require(ifp);
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_TRACE) {
char source_str[100]; zlog_debug("%s: to %s: (S,G)=%s pref=%u metric=%u rpt_bit=%u",
char group_str[100];
pim_inet4_dump("<src?>", ch->source_addr, source_str, sizeof(source_str));
pim_inet4_dump("<grp?>", ch->group_addr, group_str, sizeof(group_str));
zlog_debug("%s: to %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
ifp->name, source_str, group_str, ifp->name, ch->sg_str,
metric.metric_preference, metric.metric_preference,
metric.route_metric, metric.route_metric,
PIM_FORCE_BOOLEAN(metric.rpt_bit_flag)); PIM_FORCE_BOOLEAN(metric.rpt_bit_flag));
} }
if (pim_msg_send(pim_ifp->pim_sock_fd, if (pim_msg_send(pim_ifp->pim_sock_fd,
pim_ifp->primary_address,
qpim_all_pim_routers_addr, qpim_all_pim_routers_addr,
pim_msg, pim_msg,
pim_msg_size, pim_msg_size,
@ -523,7 +510,7 @@ static int pim_assert_cancel(struct pim_ifchannel *ch)
metric.rpt_bit_flag = 0; metric.rpt_bit_flag = 0;
metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX; metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX;
metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX; metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX;
metric.ip_address = ch->source_addr; metric.ip_address = ch->sg.src;
return pim_assert_do(ch, metric); return pim_assert_do(ch, metric);
} }
@ -533,28 +520,20 @@ static int on_assert_timer(struct thread *t)
struct pim_ifchannel *ch; struct pim_ifchannel *ch;
struct interface *ifp; struct interface *ifp;
zassert(t);
ch = THREAD_ARG(t); ch = THREAD_ARG(t);
zassert(ch);
ifp = ch->interface; ifp = ch->interface;
zassert(ifp);
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_TRACE) {
char src_str[100]; zlog_debug("%s: (S,G)=%s timer expired on interface %s",
char grp_str[100];
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
zlog_debug("%s: (S,G)=(%s,%s) timer expired on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str, ifp->name); ch->sg_str, ifp->name);
} }
ch->t_ifassert_timer = 0; ch->t_ifassert_timer = NULL;
switch (ch->ifassert_state) { switch (ch->ifassert_state) {
case PIM_IFASSERT_I_AM_WINNER: case PIM_IFASSERT_I_AM_WINNER:
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
assert_action_a3(ch); assert_action_a3(ch);
break; break;
case PIM_IFASSERT_I_AM_LOSER: case PIM_IFASSERT_I_AM_LOSER:
@ -562,13 +541,10 @@ static int on_assert_timer(struct thread *t)
break; break;
default: default:
{ {
char source_str[100]; if (PIM_DEBUG_PIM_EVENTS)
char group_str[100]; zlog_warn("%s: (S,G)=%s invalid assert state %d on interface %s",
pim_inet4_dump("<src?>", ch->source_addr, source_str, sizeof(source_str)); __PRETTY_FUNCTION__,
pim_inet4_dump("<grp?>", ch->group_addr, group_str, sizeof(group_str)); ch->sg_str, ch->ifassert_state, ifp->name);
zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s",
__PRETTY_FUNCTION__,
source_str, group_str, ch->ifassert_state, ifp->name);
} }
} }
@ -577,46 +553,25 @@ static int on_assert_timer(struct thread *t)
static void assert_timer_off(struct pim_ifchannel *ch) static void assert_timer_off(struct pim_ifchannel *ch)
{ {
struct interface *ifp;
zassert(ch);
ifp = ch->interface;
zassert(ifp);
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_TRACE) {
if (ch->t_ifassert_timer) { if (ch->t_ifassert_timer) {
char src_str[100]; zlog_debug("%s: (S,G)=%s cancelling timer on interface %s",
char grp_str[100];
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
zlog_debug("%s: (S,G)=(%s,%s) cancelling timer on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str, ifp->name); ch->sg_str, ch->interface->name);
} }
} }
THREAD_OFF(ch->t_ifassert_timer); THREAD_OFF(ch->t_ifassert_timer);
zassert(!ch->t_ifassert_timer);
} }
static void pim_assert_timer_set(struct pim_ifchannel *ch, static void pim_assert_timer_set(struct pim_ifchannel *ch,
int interval) int interval)
{ {
struct interface *ifp;
zassert(ch);
ifp = ch->interface;
zassert(ifp);
assert_timer_off(ch); assert_timer_off(ch);
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_TRACE) {
char src_str[100]; zlog_debug("%s: (S,G)=%s starting %u sec timer on interface %s",
char grp_str[100];
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
zlog_debug("%s: (S,G)=(%s,%s) starting %u sec timer on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str, interval, ifp->name); ch->sg_str, interval, ch->interface->name);
} }
THREAD_TIMER_ON(master, ch->t_ifassert_timer, THREAD_TIMER_ON(master, ch->t_ifassert_timer,
@ -644,17 +599,11 @@ int assert_action_a1(struct pim_ifchannel *ch)
struct interface *ifp = ch->interface; struct interface *ifp = ch->interface;
struct pim_interface *pim_ifp; struct pim_interface *pim_ifp;
zassert(ifp);
pim_ifp = ifp->info; pim_ifp = ifp->info;
if (!pim_ifp) { if (!pim_ifp) {
char src_str[100]; zlog_warn("%s: (S,G)=%s multicast not enabled on interface %s",
char grp_str[100];
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
zlog_warn("%s: (S,G)=(%s,%s) multicast not enabled on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str, ifp->name); ch->sg_str, ifp->name);
return -1; /* must return since pim_ifp is used below */ return -1; /* must return since pim_ifp is used below */
} }
@ -664,19 +613,19 @@ int assert_action_a1(struct pim_ifchannel *ch)
pim_macro_spt_assert_metric(&ch->upstream->rpf, pim_macro_spt_assert_metric(&ch->upstream->rpf,
pim_ifp->primary_address)); pim_ifp->primary_address));
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
if (assert_action_a3(ch)) { if (assert_action_a3(ch)) {
char src_str[100]; zlog_warn("%s: (S,G)=%s assert_action_a3 failure on interface %s",
char grp_str[100];
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
zlog_warn("%s: (S,G)=(%s,%s) assert_action_a3 failure on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str, ifp->name); ch->sg_str, ifp->name);
/* warning only */ /* warning only */
} }
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); if (ch->ifassert_state != PIM_IFASSERT_I_AM_WINNER)
{
if (PIM_DEBUG_PIM_EVENTS)
zlog_warn("%s: channel%s not in expected PIM_IFASSERT_I_AM_WINNER state",
__PRETTY_FUNCTION__, ch->sg_str);
}
return 0; return 0;
} }
@ -699,7 +648,12 @@ static void assert_action_a2(struct pim_ifchannel *ch,
pim_assert_timer_set(ch, PIM_ASSERT_TIME); pim_assert_timer_set(ch, PIM_ASSERT_TIME);
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER); if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
{
if (PIM_DEBUG_PIM_EVENTS)
zlog_warn("%s: channel%s not in expected PIM_IFASSERT_I_AM_LOSER state",
__PRETTY_FUNCTION__, ch->sg_str);
}
} }
/* /*
@ -712,24 +666,23 @@ static void assert_action_a2(struct pim_ifchannel *ch,
*/ */
static int assert_action_a3(struct pim_ifchannel *ch) static int assert_action_a3(struct pim_ifchannel *ch)
{ {
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); if (ch->ifassert_state != PIM_IFASSERT_I_AM_WINNER)
{
if (PIM_DEBUG_PIM_EVENTS)
zlog_warn("%s: channel%s expected to be in PIM_IFASSERT_I_AM_WINNER state",
__PRETTY_FUNCTION__, ch->sg_str);
return -1;
}
pim_assert_timer_reset(ch); pim_assert_timer_reset(ch);
if (pim_assert_send(ch)) { if (pim_assert_send(ch)) {
char src_str[100]; zlog_warn("%s: (S,G)=%s failure sending assert on interface %s",
char grp_str[100];
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
zlog_warn("%s: (S,G)=(%s,%s) failure sending assert on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str, ch->interface->name); ch->sg_str, ch->interface->name);
return -1; return -1;
} }
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
return 0; return 0;
} }
@ -746,19 +699,20 @@ static int assert_action_a3(struct pim_ifchannel *ch)
void assert_action_a4(struct pim_ifchannel *ch) void assert_action_a4(struct pim_ifchannel *ch)
{ {
if (pim_assert_cancel(ch)) { if (pim_assert_cancel(ch)) {
char src_str[100]; zlog_warn("%s: failure sending AssertCancel%s on interface %s",
char grp_str[100];
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
zlog_warn("%s: failure sending AssertCancel(%s,%s) on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str, ch->interface->name); ch->sg_str, ch->interface->name);
/* log warning only */ /* log warning only */
} }
assert_action_a5(ch); assert_action_a5(ch);
zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO); if (ch->ifassert_state != PIM_IFASSERT_NOINFO)
{
if (PIM_DEBUG_PIM_EVENTS)
zlog_warn("%s: channel%s not in PIM_IFASSERT_NOINFO state as expected",
__PRETTY_FUNCTION__, ch->sg_str);
}
} }
/* /*
@ -772,7 +726,12 @@ void assert_action_a4(struct pim_ifchannel *ch)
void assert_action_a5(struct pim_ifchannel *ch) void assert_action_a5(struct pim_ifchannel *ch)
{ {
reset_ifassert_state(ch); reset_ifassert_state(ch);
zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO); if (ch->ifassert_state != PIM_IFASSERT_NOINFO)
{
if (PIM_DEBUG_PIM_EVENTS)
zlog_warn("%s: channel%s not in PIM_IFSSERT_NOINFO state as expected",
__PRETTY_FUNCTION__, ch->sg_str);
}
} }
/* /*
@ -799,6 +758,11 @@ static void assert_action_a6(struct pim_ifchannel *ch,
if (ch->upstream->join_state == PIM_UPSTREAM_JOINED) if (ch->upstream->join_state == PIM_UPSTREAM_JOINED)
ch->upstream->sptbit = PIM_UPSTREAM_SPTBIT_TRUE; ch->upstream->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER); if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
{
if(PIM_DEBUG_PIM_EVENTS)
zlog_warn("%s: channel%s not in PIM_IFASSERT_I_AM_LOSER state as expected",
__PRETTY_FUNCTION__, ch->sg_str);
}
} }

View File

@ -30,8 +30,7 @@
#include "linklist.h" #include "linklist.h"
struct pim_br { struct pim_br {
struct in_addr source; struct prefix_sg sg;
struct in_addr group;
struct in_addr pmbr; struct in_addr pmbr;
}; };
@ -40,14 +39,14 @@ struct in_addr pim_br_unknown = { .s_addr = 0 };
static struct list *pim_br_list = NULL; static struct list *pim_br_list = NULL;
struct in_addr struct in_addr
pim_br_get_pmbr (struct in_addr source, struct in_addr group) pim_br_get_pmbr (struct prefix_sg *sg)
{ {
struct listnode *node; struct listnode *node;
struct pim_br *pim_br; struct pim_br *pim_br;
for (ALL_LIST_ELEMENTS_RO (pim_br_list, node, pim_br)) { for (ALL_LIST_ELEMENTS_RO (pim_br_list, node, pim_br)) {
if (source.s_addr == pim_br->source.s_addr && if (sg->src.s_addr == pim_br->sg.src.s_addr &&
group.s_addr == pim_br->group.s_addr) sg->grp.s_addr == pim_br->sg.grp.s_addr)
return pim_br->pmbr; return pim_br->pmbr;
} }
@ -55,14 +54,14 @@ pim_br_get_pmbr (struct in_addr source, struct in_addr group)
} }
void void
pim_br_set_pmbr (struct in_addr source, struct in_addr group, struct in_addr br) pim_br_set_pmbr (struct prefix_sg *sg, struct in_addr br)
{ {
struct listnode *node, *next; struct listnode *node, *next;
struct pim_br *pim_br; struct pim_br *pim_br;
for (ALL_LIST_ELEMENTS (pim_br_list, node, next, pim_br)) { for (ALL_LIST_ELEMENTS (pim_br_list, node, next, pim_br)) {
if (source.s_addr == pim_br->source.s_addr && if (sg->src.s_addr == pim_br->sg.src.s_addr &&
group.s_addr == pim_br->group.s_addr) sg->grp.s_addr == pim_br->sg.grp.s_addr)
break; break;
} }
@ -73,8 +72,7 @@ pim_br_set_pmbr (struct in_addr source, struct in_addr group, struct in_addr br)
return; return;
} }
pim_br->source = source; pim_br->sg = *sg;
pim_br->group = group;
listnode_add(pim_br_list, pim_br); listnode_add(pim_br_list, pim_br);
} }
@ -86,14 +84,14 @@ pim_br_set_pmbr (struct in_addr source, struct in_addr group, struct in_addr br)
* Remove the (S,G) from the stored values * Remove the (S,G) from the stored values
*/ */
void void
pim_br_clear_pmbr (struct in_addr source, struct in_addr group) pim_br_clear_pmbr (struct prefix_sg *sg)
{ {
struct listnode *node, *next; struct listnode *node, *next;
struct pim_br *pim_br; struct pim_br *pim_br;
for (ALL_LIST_ELEMENTS (pim_br_list, node, next, pim_br)) { for (ALL_LIST_ELEMENTS (pim_br_list, node, next, pim_br)) {
if (source.s_addr == pim_br->source.s_addr && if (sg->src.s_addr == pim_br->sg.src.s_addr &&
group.s_addr == pim_br->group.s_addr) sg->grp.s_addr == pim_br->sg.grp.s_addr)
break; break;
} }

View File

@ -21,10 +21,10 @@
#ifndef PIM_BR_H #ifndef PIM_BR_H
#define PIM_BR_H #define PIM_BR_H
struct in_addr pim_br_get_pmbr (struct in_addr source, struct in_addr group); struct in_addr pim_br_get_pmbr (struct prefix_sg *sg);
void pim_br_set_pmbr (struct in_addr source, struct in_addr group, struct in_addr value); void pim_br_set_pmbr (struct prefix_sg *sg, struct in_addr value);
void pim_br_clear_pmbr (struct in_addr source, struct in_addr group); void pim_br_clear_pmbr (struct prefix_sg *sg);
void pim_br_init (void); void pim_br_init (void);

File diff suppressed because it is too large Load Diff

View File

@ -47,6 +47,7 @@
#define DEBUG_PIM_PACKETS_STR "PIM protocol packets\n" #define DEBUG_PIM_PACKETS_STR "PIM protocol packets\n"
#define DEBUG_PIM_HELLO_PACKETS_STR "PIM Hello protocol packets\n" #define DEBUG_PIM_HELLO_PACKETS_STR "PIM Hello protocol packets\n"
#define DEBUG_PIM_J_P_PACKETS_STR "PIM Join/Prune protocol packets\n" #define DEBUG_PIM_J_P_PACKETS_STR "PIM Join/Prune protocol packets\n"
#define DEBUG_PIM_PIM_REG_PACKETS_STR "PIM Register/Reg-Stop protocol packets\n"
#define DEBUG_PIM_PACKETDUMP_STR "PIM packet dump\n" #define DEBUG_PIM_PACKETDUMP_STR "PIM packet dump\n"
#define DEBUG_PIM_PACKETDUMP_SEND_STR "Dump sent packets\n" #define DEBUG_PIM_PACKETDUMP_SEND_STR "Dump sent packets\n"
#define DEBUG_PIM_PACKETDUMP_RECV_STR "Dump received packets\n" #define DEBUG_PIM_PACKETDUMP_RECV_STR "Dump received packets\n"
@ -57,6 +58,12 @@
#define CLEAR_IP_PIM_STR "PIM clear commands\n" #define CLEAR_IP_PIM_STR "PIM clear commands\n"
#define MROUTE_STR "IP multicast routing table\n" #define MROUTE_STR "IP multicast routing table\n"
#define RIB_STR "IP unicast routing table\n" #define RIB_STR "IP unicast routing table\n"
#define CFG_MSDP_STR "Configure multicast source discovery protocol\n"
#define MSDP_STR "MSDP information\n"
#define DEBUG_MSDP_STR "MSDP protocol activity\n"
#define DEBUG_MSDP_EVENTS_STR "MSDP protocol events\n"
#define DEBUG_MSDP_INTERNAL_STR "MSDP protocol internal\n"
#define DEBUG_MSDP_PACKETS_STR "MSDP protocol packets\n"
void pim_cmd_init(void); void pim_cmd_init(void);

View File

@ -37,7 +37,7 @@ static void on_trace(const char *label,
struct interface *ifp, struct in_addr src) struct interface *ifp, struct in_addr src)
{ {
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_TRACE) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
zlog_debug("%s: from %s on %s", zlog_debug("%s: from %s on %s",
label, src_str, ifp->name); label, src_str, ifp->name);
@ -49,7 +49,7 @@ static void tlv_trace_bool(const char *label, const char *tlv_name,
int isset, int value) int isset, int value)
{ {
if (isset) { if (isset) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: PIM hello option from %s on interface %s: %s=%d", zlog_debug("%s: PIM hello option from %s on interface %s: %s=%d",
label, label,
@ -63,7 +63,7 @@ static void tlv_trace_uint16(const char *label, const char *tlv_name,
int isset, uint16_t value) int isset, uint16_t value)
{ {
if (isset) { if (isset) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u", zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u",
label, label,
@ -77,7 +77,7 @@ static void tlv_trace_uint32(const char *label, const char *tlv_name,
int isset, uint32_t value) int isset, uint32_t value)
{ {
if (isset) { if (isset) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u", zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u",
label, label,
@ -91,7 +91,7 @@ static void tlv_trace_uint32_hex(const char *label, const char *tlv_name,
int isset, uint32_t value) int isset, uint32_t value)
{ {
if (isset) { if (isset) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: PIM hello option from %s on interface %s: %s=%08x", zlog_debug("%s: PIM hello option from %s on interface %s: %s=%08x",
label, label,
@ -106,7 +106,7 @@ static void tlv_trace(const char *label, const char *tlv_name,
int isset) int isset)
{ {
if (isset) { if (isset) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: PIM hello option from %s on interface %s: %s", zlog_debug("%s: PIM hello option from %s on interface %s: %s",
label, label,
@ -121,7 +121,7 @@ static void tlv_trace_list(const char *label, const char *tlv_name,
int isset, struct list *addr_list) int isset, struct list *addr_list)
{ {
if (isset) { if (isset) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: PIM hello option from %s on interface %s: %s size=%d list=%p", zlog_debug("%s: PIM hello option from %s on interface %s: %s size=%d list=%p",
label, label,
@ -181,7 +181,7 @@ int pim_hello_recv(struct interface *ifp,
if (remain < PIM_TLV_MIN_SIZE) { if (remain < PIM_TLV_MIN_SIZE) {
if (PIM_DEBUG_PIM_HELLO) { if (PIM_DEBUG_PIM_HELLO) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: short PIM hello TLV size=%d < min=%d from %s on interface %s", zlog_debug("%s: short PIM hello TLV size=%d < min=%d from %s on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -198,7 +198,7 @@ int pim_hello_recv(struct interface *ifp,
if ((tlv_curr + option_len) > tlv_pastend) { if ((tlv_curr + option_len) > tlv_pastend) {
if (PIM_DEBUG_PIM_HELLO) { if (PIM_DEBUG_PIM_HELLO) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: long PIM hello TLV type=%d length=%d > left=%td from %s on interface %s", zlog_debug("%s: long PIM hello TLV type=%d length=%d > left=%td from %s on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -209,7 +209,7 @@ int pim_hello_recv(struct interface *ifp,
} }
if (PIM_DEBUG_PIM_HELLO) { if (PIM_DEBUG_PIM_HELLO) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %s on %s", zlog_debug("%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %s on %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -267,7 +267,7 @@ int pim_hello_recv(struct interface *ifp,
break; break;
case PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH: case PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH:
if (PIM_DEBUG_PIM_HELLO) { if (PIM_DEBUG_PIM_HELLO) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %s on interface %s", zlog_debug("%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %s on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -277,7 +277,7 @@ int pim_hello_recv(struct interface *ifp,
break; break;
default: default:
if (PIM_DEBUG_PIM_HELLO) { if (PIM_DEBUG_PIM_HELLO) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: ignoring unknown PIM hello TLV type=%d length=%d from %s on interface %s", zlog_debug("%s: ignoring unknown PIM hello TLV type=%d length=%d from %s on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -326,7 +326,7 @@ int pim_hello_recv(struct interface *ifp,
if (!PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) { if (!PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) {
if (PIM_DEBUG_PIM_HELLO) { if (PIM_DEBUG_PIM_HELLO) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: PIM hello missing holdtime from %s on interface %s", zlog_debug("%s: PIM hello missing holdtime from %s on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -349,10 +349,11 @@ int pim_hello_recv(struct interface *ifp,
hello_option_override_interval, hello_option_override_interval,
hello_option_dr_priority, hello_option_dr_priority,
hello_option_generation_id, hello_option_generation_id,
hello_option_addr_list); hello_option_addr_list,
PIM_NEIGHBOR_SEND_DELAY);
if (!neigh) { if (!neigh) {
if (PIM_DEBUG_PIM_HELLO) { if (PIM_DEBUG_PIM_HELLO) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: failure creating PIM neighbor %s on interface %s", zlog_warn("%s: failure creating PIM neighbor %s on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -373,15 +374,10 @@ int pim_hello_recv(struct interface *ifp,
/* GenID mismatch ? */ /* GenID mismatch ? */
if (!PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_GENERATION_ID) || if (!PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_GENERATION_ID) ||
(hello_option_generation_id != neigh->generation_id)) { (hello_option_generation_id != neigh->generation_id)) {
/* GenID changed */
pim_upstream_rpf_genid_changed(neigh->source_addr);
/* GenID mismatch, then replace neighbor */ /* GenID mismatch, then replace neighbor */
if (PIM_DEBUG_PIM_HELLO) { if (PIM_DEBUG_PIM_HELLO) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: GenId mismatch new=%08x old=%08x: replacing neighbor %s on %s", zlog_debug("%s: GenId mismatch new=%08x old=%08x: replacing neighbor %s on %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -400,10 +396,11 @@ int pim_hello_recv(struct interface *ifp,
hello_option_override_interval, hello_option_override_interval,
hello_option_dr_priority, hello_option_dr_priority,
hello_option_generation_id, hello_option_generation_id,
hello_option_addr_list); hello_option_addr_list,
PIM_NEIGHBOR_SEND_NOW);
if (!neigh) { if (!neigh) {
if (PIM_DEBUG_PIM_HELLO) { if (PIM_DEBUG_PIM_HELLO) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: failure re-creating PIM neighbor %s on interface %s", zlog_debug("%s: failure re-creating PIM neighbor %s on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,

View File

@ -25,6 +25,8 @@
#include "memory.h" #include "memory.h"
#include "prefix.h" #include "prefix.h"
#include "vrf.h" #include "vrf.h"
#include "linklist.h"
#include "plist.h"
#include "pimd.h" #include "pimd.h"
#include "pim_iface.h" #include "pim_iface.h"
@ -38,14 +40,26 @@
#include "pim_sock.h" #include "pim_sock.h"
#include "pim_time.h" #include "pim_time.h"
#include "pim_ssmpingd.h" #include "pim_ssmpingd.h"
#include "pim_rp.h"
struct interface *pim_regiface = NULL; struct interface *pim_regiface = NULL;
struct list *pim_ifchannel_list = NULL;
static void pim_if_igmp_join_del_all(struct interface *ifp); static void pim_if_igmp_join_del_all(struct interface *ifp);
void pim_if_init() void
pim_if_init (void)
{ {
vrf_iflist_create(VRF_DEFAULT); vrf_iflist_create(VRF_DEFAULT);
pim_ifchannel_list = list_new();
pim_ifchannel_list->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
}
void
pim_if_terminate (void)
{
if (pim_ifchannel_list)
list_free (pim_ifchannel_list);
} }
static void *if_list_clean(struct pim_interface *pim_ifp) static void *if_list_clean(struct pim_interface *pim_ifp)
@ -78,15 +92,16 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
zassert(ifp); zassert(ifp);
zassert(!ifp->info); zassert(!ifp->info);
pim_ifp = XMALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp)); pim_ifp = XCALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
if (!pim_ifp) { if (!pim_ifp) {
zlog_err("PIM XMALLOC(%zu) failure", sizeof(*pim_ifp)); zlog_err("PIM XCALLOC(%zu) failure", sizeof(*pim_ifp));
return 0; return 0;
} }
pim_ifp->options = 0; pim_ifp->options = 0;
pim_ifp->mroute_vif_index = -1; pim_ifp->mroute_vif_index = -1;
pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
pim_ifp->igmp_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE; pim_ifp->igmp_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL; pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL;
pim_ifp->igmp_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC; pim_ifp->igmp_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC;
@ -104,15 +119,12 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
if (igmp) if (igmp)
PIM_IF_DO_IGMP(pim_ifp->options); PIM_IF_DO_IGMP(pim_ifp->options);
#if 0
/* FIXME: Should join? */
PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options); PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options);
#endif
pim_ifp->igmp_join_list = 0; pim_ifp->igmp_join_list = NULL;
pim_ifp->igmp_socket_list = 0; pim_ifp->igmp_socket_list = NULL;
pim_ifp->pim_neighbor_list = 0; pim_ifp->pim_neighbor_list = NULL;
pim_ifp->pim_ifchannel_list = 0; pim_ifp->pim_ifchannel_list = NULL;
pim_ifp->pim_generation_id = 0; pim_ifp->pim_generation_id = 0;
/* list of struct igmp_sock */ /* list of struct igmp_sock */
@ -141,6 +153,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
return if_list_clean(pim_ifp); return if_list_clean(pim_ifp);
} }
pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free; pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free;
pim_ifp->pim_ifchannel_list->cmp = (int (*)(void *, void *)) pim_ifchannel_compare;
ifp->info = pim_ifp; ifp->info = pim_ifp;
@ -164,16 +177,11 @@ void pim_if_delete(struct interface *ifp)
if (pim_ifp->igmp_join_list) { if (pim_ifp->igmp_join_list) {
pim_if_igmp_join_del_all(ifp); pim_if_igmp_join_del_all(ifp);
} }
zassert(!pim_ifp->igmp_join_list);
zassert(pim_ifp->igmp_socket_list); pim_ifchannel_delete_all (ifp);
zassert(!listcount(pim_ifp->igmp_socket_list)); igmp_sock_delete_all (ifp);
zassert(pim_ifp->pim_neighbor_list); pim_neighbor_delete_all (ifp, "Interface removed from configuration");
zassert(!listcount(pim_ifp->pim_neighbor_list));
zassert(pim_ifp->pim_ifchannel_list);
zassert(!listcount(pim_ifp->pim_ifchannel_list));
if (PIM_MROUTE_IS_ENABLED) { if (PIM_MROUTE_IS_ENABLED) {
pim_if_del_vif(ifp); pim_if_del_vif(ifp);
@ -185,7 +193,7 @@ void pim_if_delete(struct interface *ifp)
XFREE(MTYPE_PIM_INTERFACE, pim_ifp); XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
ifp->info = 0; ifp->info = NULL;
} }
void pim_if_update_could_assert(struct interface *ifp) void pim_if_update_could_assert(struct interface *ifp)
@ -258,14 +266,10 @@ static int detect_primary_address_change(struct interface *ifp,
int force_prim_as_any, int force_prim_as_any,
const char *caller) const char *caller)
{ {
struct pim_interface *pim_ifp; struct pim_interface *pim_ifp = ifp->info;
struct in_addr new_prim_addr; struct in_addr new_prim_addr;
int changed; int changed;
pim_ifp = ifp->info;
if (!pim_ifp)
return 0;
if (force_prim_as_any) if (force_prim_as_any)
new_prim_addr = qpim_inaddr_any; new_prim_addr = qpim_inaddr_any;
else else
@ -274,8 +278,8 @@ static int detect_primary_address_change(struct interface *ifp,
changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr; changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr;
if (PIM_DEBUG_ZEBRA) { if (PIM_DEBUG_ZEBRA) {
char new_prim_str[100]; char new_prim_str[INET_ADDRSTRLEN];
char old_prim_str[100]; char old_prim_str[INET_ADDRSTRLEN];
pim_inet4_dump("<new?>", new_prim_addr, new_prim_str, sizeof(new_prim_str)); pim_inet4_dump("<new?>", new_prim_addr, new_prim_str, sizeof(new_prim_str));
pim_inet4_dump("<old?>", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str)); pim_inet4_dump("<old?>", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str));
zlog_debug("%s: old=%s new=%s on interface %s: %s", zlog_debug("%s: old=%s new=%s on interface %s: %s",
@ -286,57 +290,230 @@ static int detect_primary_address_change(struct interface *ifp,
if (changed) { if (changed) {
pim_ifp->primary_address = new_prim_addr; pim_ifp->primary_address = new_prim_addr;
if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
return changed;
}
pim_addr_change(ifp);
} }
return changed; return changed;
} }
static void detect_secondary_address_change(struct interface *ifp, static int pim_sec_addr_comp(const void *p1, const void *p2)
{
const struct pim_secondary_addr *sec1 = p1;
const struct pim_secondary_addr *sec2 = p2;
if (ntohl(sec1->addr.s_addr) < ntohl(sec2->addr.s_addr))
return -1;
if (ntohl(sec1->addr.s_addr) > ntohl(sec2->addr.s_addr))
return 1;
return 0;
}
static void pim_sec_addr_free(struct pim_secondary_addr *sec_addr)
{
XFREE(MTYPE_PIM_SEC_ADDR, sec_addr);
}
static struct pim_secondary_addr *
pim_sec_addr_find(struct pim_interface *pim_ifp, struct in_addr addr)
{
struct pim_secondary_addr *sec_addr;
struct listnode *node;
if (!pim_ifp->sec_addr_list) {
return NULL;
}
for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
if (sec_addr->addr.s_addr == addr.s_addr) {
return sec_addr;
}
}
return NULL;
}
static void pim_sec_addr_del(struct pim_interface *pim_ifp,
struct pim_secondary_addr *sec_addr)
{
listnode_delete(pim_ifp->sec_addr_list, sec_addr);
pim_sec_addr_free(sec_addr);
}
static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct in_addr addr)
{
int changed = 0;
struct pim_secondary_addr *sec_addr;
sec_addr = pim_sec_addr_find(pim_ifp, addr);
if (sec_addr) {
sec_addr->flags &= ~PIM_SEC_ADDRF_STALE;
return changed;
}
if (!pim_ifp->sec_addr_list) {
pim_ifp->sec_addr_list = list_new();
pim_ifp->sec_addr_list->del = (void (*)(void *))pim_sec_addr_free;
pim_ifp->sec_addr_list->cmp = (int (*)(void *, void *))pim_sec_addr_comp;
}
sec_addr = XCALLOC(MTYPE_PIM_SEC_ADDR, sizeof(*sec_addr));
if (!sec_addr) {
if (list_isempty(pim_ifp->sec_addr_list)) {
list_free(pim_ifp->sec_addr_list);
pim_ifp->sec_addr_list = NULL;
}
return changed;
}
changed = 1;
sec_addr->addr = addr;
listnode_add_sort(pim_ifp->sec_addr_list, sec_addr);
return changed;
}
static int pim_sec_addr_del_all(struct pim_interface *pim_ifp)
{
int changed = 0;
if (!pim_ifp->sec_addr_list) {
return changed;
}
if (!list_isempty(pim_ifp->sec_addr_list)) {
changed = 1;
/* remove all nodes and free up the list itself */
list_delete_all_node(pim_ifp->sec_addr_list);
list_free(pim_ifp->sec_addr_list);
pim_ifp->sec_addr_list = NULL;
}
return changed;
}
static int pim_sec_addr_update(struct interface *ifp)
{
struct pim_interface *pim_ifp = ifp->info;
struct connected *ifc;
struct listnode *node;
struct listnode *nextnode;
struct pim_secondary_addr *sec_addr;
int changed = 0;
if (pim_ifp->sec_addr_list) {
for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
sec_addr->flags |= PIM_SEC_ADDRF_STALE;
}
}
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
struct prefix *p = ifc->address;
if (p->family != AF_INET) {
continue;
}
if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
continue;
}
if (pim_ifp->primary_address.s_addr == p->u.prefix4.s_addr) {
/* don't add the primary address into the secondary address list */
continue;
}
if (pim_sec_addr_add(pim_ifp, p->u.prefix4)) {
changed = 1;
}
}
if (pim_ifp->sec_addr_list) {
/* Drop stale entries */
for (ALL_LIST_ELEMENTS(pim_ifp->sec_addr_list, node, nextnode, sec_addr)) {
if (sec_addr->flags & PIM_SEC_ADDRF_STALE) {
pim_sec_addr_del(pim_ifp, sec_addr);
changed = 1;
}
}
/* If the list went empty free it up */
if (list_isempty(pim_ifp->sec_addr_list)) {
list_free(pim_ifp->sec_addr_list);
pim_ifp->sec_addr_list = NULL;
}
}
return changed;
}
static int detect_secondary_address_change(struct interface *ifp,
int force_prim_as_any,
const char *caller) const char *caller)
{ {
struct pim_interface *pim_ifp; struct pim_interface *pim_ifp = ifp->info;
int changed; int changed = 0;
pim_ifp = ifp->info; if (force_prim_as_any) {
if (!pim_ifp) /* if primary address is being forced to zero just flush the
return; * secondary address list */
changed = pim_sec_addr_del_all(pim_ifp);
changed = 1; /* true */ } else {
if (PIM_DEBUG_ZEBRA) /* re-evaluate the secondary address list */
zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change", changed = pim_sec_addr_update(ifp);
__PRETTY_FUNCTION__, ifp->name);
if (!changed) {
return;
} }
if (!PIM_IF_TEST_PIM(pim_ifp->options)) { return changed;
return;
}
pim_addr_change(ifp);
} }
static void detect_address_change(struct interface *ifp, static void detect_address_change(struct interface *ifp,
int force_prim_as_any, int force_prim_as_any,
const char *caller) const char *caller)
{ {
int prim_changed; int changed = 0;
struct pim_interface *pim_ifp;
prim_changed = detect_primary_address_change(ifp, force_prim_as_any, caller); pim_ifp = ifp->info;
if (prim_changed) { if (!pim_ifp)
/* no need to detect secondary change because
the reaction would be the same */
return; return;
if (detect_primary_address_change(ifp, force_prim_as_any, caller)) {
changed = 1;
} }
detect_secondary_address_change(ifp, caller); if (detect_secondary_address_change(ifp, force_prim_as_any, caller)) {
changed = 1;
}
if (changed) {
if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
return;
}
pim_addr_change(ifp);
}
/* XXX: if we have unnumbered interfaces we need to run detect address
* address change on all of them when the lo address changes */
}
int pim_update_source_set(struct interface *ifp, struct in_addr source)
{
struct pim_interface *pim_ifp = ifp->info;
if (!pim_ifp) {
return PIM_IFACE_NOT_FOUND;
}
if (pim_ifp->update_source.s_addr == source.s_addr) {
return PIM_UPDATE_SOURCE_DUP;
}
pim_ifp->update_source = source;
detect_address_change(ifp, 0 /* force_prim_as_any */,
__PRETTY_FUNCTION__);
return PIM_SUCCESS;
} }
void pim_if_addr_add(struct connected *ifc) void pim_if_addr_add(struct connected *ifc)
@ -406,6 +583,7 @@ void pim_if_addr_add(struct connected *ifc)
if (pim_ifp->mroute_vif_index < 0) { if (pim_ifp->mroute_vif_index < 0) {
pim_if_add_vif(ifp); pim_if_add_vif(ifp);
} }
pim_ifchannel_scan_forward_start (ifp);
} }
} }
@ -496,19 +674,59 @@ void pim_if_addr_add_all(struct interface *ifp)
struct connected *ifc; struct connected *ifc;
struct listnode *node; struct listnode *node;
struct listnode *nextnode; struct listnode *nextnode;
int v4_addrs = 0;
int v6_addrs = 0;
struct pim_interface *pim_ifp = ifp->info;
/* PIM/IGMP enabled ? */ /* PIM/IGMP enabled ? */
if (!ifp->info) if (!pim_ifp)
return; return;
for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) { for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
struct prefix *p = ifc->address; struct prefix *p = ifc->address;
if (p->family != AF_INET) if (p->family != AF_INET)
continue; {
v6_addrs++;
continue;
}
v4_addrs++;
pim_if_addr_add(ifc); pim_if_addr_add(ifc);
} }
if (!v4_addrs && v6_addrs && !if_is_loopback (ifp))
{
if (PIM_IF_TEST_PIM(pim_ifp->options)) {
/* Interface has a valid primary address ? */
if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
/* Interface has a valid socket ? */
if (pim_ifp->pim_sock_fd < 0) {
if (pim_sock_add(ifp)) {
zlog_warn("Failure creating PIM socket for interface %s",
ifp->name);
}
}
}
} /* pim */
}
if (PIM_MROUTE_IS_ENABLED) {
/*
* PIM or IGMP is enabled on interface, and there is at least one
* address assigned, then try to create a vif_index.
*/
if (pim_ifp->mroute_vif_index < 0) {
pim_if_add_vif(ifp);
}
pim_ifchannel_scan_forward_start (ifp);
}
pim_rp_setup();
pim_rp_check_on_if_add(pim_ifp);
} }
void pim_if_addr_del_all(struct interface *ifp) void pim_if_addr_del_all(struct interface *ifp)
@ -529,6 +747,9 @@ void pim_if_addr_del_all(struct interface *ifp)
pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */); pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
} }
pim_rp_setup();
pim_i_am_rp_re_evaluate();
} }
void pim_if_addr_del_all_igmp(struct interface *ifp) void pim_if_addr_del_all_igmp(struct interface *ifp)
@ -571,17 +792,28 @@ void pim_if_addr_del_all_pim(struct interface *ifp)
} }
} }
static struct in_addr find_first_nonsec_addr(struct interface *ifp) struct in_addr
pim_find_primary_addr (struct interface *ifp)
{ {
struct connected *ifc; struct connected *ifc;
struct listnode *node; struct listnode *node;
struct in_addr addr; struct in_addr addr;
int v4_addrs = 0;
int v6_addrs = 0;
struct pim_interface *pim_ifp = ifp->info;
if (pim_ifp && PIM_INADDR_ISNOT_ANY(pim_ifp->update_source)) {
return pim_ifp->update_source;
}
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
struct prefix *p = ifc->address; struct prefix *p = ifc->address;
if (p->family != AF_INET) if (p->family != AF_INET)
continue; {
v6_addrs++;
continue;
}
if (PIM_INADDR_IS_ANY(p->u.prefix4)) { if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
zlog_warn("%s: null IPv4 address connected to interface %s", zlog_warn("%s: null IPv4 address connected to interface %s",
@ -589,22 +821,33 @@ static struct in_addr find_first_nonsec_addr(struct interface *ifp)
continue; continue;
} }
v4_addrs++;
if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
continue; continue;
return p->u.prefix4; return p->u.prefix4;
} }
/*
* If we have no v4_addrs and v6 is configured
* We probably are using unnumbered
* So let's grab the loopbacks v4 address
* and use that as the primary address
*/
if (!v4_addrs && v6_addrs && !if_is_loopback (ifp))
{
struct interface *lo_ifp;
lo_ifp = if_lookup_by_name_vrf ("lo", VRF_DEFAULT);
if (lo_ifp)
return pim_find_primary_addr (lo_ifp);
}
addr.s_addr = PIM_NET_INADDR_ANY; addr.s_addr = PIM_NET_INADDR_ANY;
return addr; return addr;
} }
struct in_addr pim_find_primary_addr(struct interface *ifp)
{
return find_first_nonsec_addr(ifp);
}
static int pim_iface_vif_index = 0; static int pim_iface_vif_index = 0;
static int static int
@ -800,9 +1043,9 @@ int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex)
struct interface *ifp; struct interface *ifp;
ifp = if_lookup_by_index_vrf (ifindex, VRF_DEFAULT); ifp = if_lookup_by_index_vrf (ifindex, VRF_DEFAULT);
pim_ifp = ifp->info; if (!ifp || !ifp->info)
if (!pim_ifp)
return -1; return -1;
pim_ifp = ifp->info;
return pim_ifp->mroute_vif_index; return pim_ifp->mroute_vif_index;
} }
@ -899,14 +1142,14 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
} }
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_TRACE) {
char addr_str[100]; char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s: neighbor not found for address %s on interface %s", zlog_debug("%s: neighbor not found for address %s on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
addr_str, ifp->name); addr_str, ifp->name);
} }
return 0; return NULL;
} }
long pim_if_t_suppressed_msec(struct interface *ifp) long pim_if_t_suppressed_msec(struct interface *ifp)
@ -985,8 +1228,8 @@ static struct igmp_join *igmp_join_new(struct interface *ifp,
join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr); join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr);
if (join_fd < 0) { if (join_fd < 0) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s", zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
@ -995,13 +1238,13 @@ static struct igmp_join *igmp_join_new(struct interface *ifp,
return 0; return 0;
} }
ij = XMALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij)); ij = XCALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
if (!ij) { if (!ij) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_err("%s: XMALLOC(%zu) failure for IGMP group %s source %s on interface %s", zlog_err("%s: XCALLOC(%zu) failure for IGMP group %s source %s on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
sizeof(*ij), group_str, source_str, ifp->name); sizeof(*ij), group_str, source_str, ifp->name);
close(join_fd); close(join_fd);
@ -1045,8 +1288,8 @@ int pim_if_igmp_join_add(struct interface *ifp,
ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr); ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
if (ij) { if (ij) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s", zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
@ -1057,8 +1300,8 @@ int pim_if_igmp_join_add(struct interface *ifp,
ij = igmp_join_new(ifp, group_addr, source_addr); ij = igmp_join_new(ifp, group_addr, source_addr);
if (!ij) { if (!ij) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s", zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
@ -1068,8 +1311,8 @@ int pim_if_igmp_join_add(struct interface *ifp,
} }
if (PIM_DEBUG_IGMP_EVENTS) { if (PIM_DEBUG_IGMP_EVENTS) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s", zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
@ -1106,8 +1349,8 @@ int pim_if_igmp_join_del(struct interface *ifp,
ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr); ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
if (!ij) { if (!ij) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: could not find IGMP group %s source %s on interface %s", zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
@ -1117,14 +1360,13 @@ int pim_if_igmp_join_del(struct interface *ifp,
} }
if (close(ij->sock_fd)) { if (close(ij->sock_fd)) {
int e = errno; char group_str[INET_ADDRSTRLEN];
char group_str[100]; char source_str[INET_ADDRSTRLEN];
char source_str[100];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s", zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
ij->sock_fd, group_str, source_str, ifp->name, e, safe_strerror(e)); ij->sock_fd, group_str, source_str, ifp->name, errno, safe_strerror(errno));
/* warning only */ /* warning only */
} }
listnode_delete(pim_ifp->igmp_join_list, ij); listnode_delete(pim_ifp->igmp_join_list, ij);
@ -1249,3 +1491,40 @@ void pim_if_create_pimreg (void)
pim_if_new(pim_regiface, 0, 0); pim_if_new(pim_regiface, 0, 0);
} }
} }
int
pim_if_connected_to_source (struct interface *ifp, struct in_addr src)
{
struct listnode *cnode;
struct connected *c;
struct prefix p;
p.family = AF_INET;
p.u.prefix4 = src;
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 1;
}
}
return 0;
}
struct interface *
pim_if_lookup_address_vrf (struct in_addr src, vrf_id_t vrf_id)
{
struct listnode *ifnode;
struct interface *ifp;
for (ALL_LIST_ELEMENTS_RO (vrf_iflist(vrf_id), ifnode, ifp))
{
if (pim_if_connected_to_source (ifp, src) && ifp->info)
return ifp;
}
return NULL;
}

View File

@ -16,7 +16,7 @@
along with this program; see the file COPYING; if not, write to the along with this program; see the file COPYING; if not, write to the
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
MA 02110-1301 USA MA 02110-1301 USA
*/ */
#ifndef PIM_IFACE_H #ifndef PIM_IFACE_H
#define PIM_IFACE_H #define PIM_IFACE_H
@ -58,12 +58,26 @@ enum pim_interface_type {
PIM_INTERFACE_SM PIM_INTERFACE_SM
}; };
enum pim_secondary_addr_flags {
PIM_SEC_ADDRF_NONE = 0,
PIM_SEC_ADDRF_STALE = (1 << 0)
};
struct pim_secondary_addr {
struct in_addr addr;
enum pim_secondary_addr_flags flags;
};
struct pim_interface { struct pim_interface {
enum pim_interface_type itype; enum pim_interface_type itype;
uint32_t options; /* bit vector */ uint32_t options; /* bit vector */
ifindex_t mroute_vif_index; ifindex_t mroute_vif_index;
struct in_addr primary_address; /* remember addr to detect change */ struct in_addr primary_address; /* remember addr to detect change */
struct list *sec_addr_list; /* list of struct pim_secondary_addr */
struct in_addr update_source; /* user can statically set the primary
* address of the interface */
int igmp_version; /* IGMP version */
int igmp_default_robustness_variable; /* IGMPv3 QRV */ int igmp_default_robustness_variable; /* IGMPv3 QRV */
int igmp_default_query_interval; /* IGMPv3 secs between general queries */ int igmp_default_query_interval; /* IGMPv3 secs between general queries */
int igmp_query_max_response_time_dsec; /* IGMPv3 Max Response Time in dsecs for general queries */ int igmp_query_max_response_time_dsec; /* IGMPv3 Max Response Time in dsecs for general queries */
@ -106,6 +120,7 @@ struct pim_interface {
}; };
extern struct interface *pim_regiface; extern struct interface *pim_regiface;
extern struct list *pim_ifchannel_list;
/* /*
if default_holdtime is set (>= 0), use it; if default_holdtime is set (>= 0), use it;
otherwise default_holdtime is 3.5 * hello_period otherwise default_holdtime is 3.5 * hello_period
@ -116,6 +131,7 @@ extern struct interface *pim_regiface;
((pim_ifp)->pim_default_holdtime)) ((pim_ifp)->pim_default_holdtime))
void pim_if_init(void); void pim_if_init(void);
void pim_if_terminate (void);
struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim); struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim);
void pim_if_delete(struct interface *ifp); void pim_if_delete(struct interface *ifp);
@ -126,6 +142,8 @@ void pim_if_addr_del_all(struct interface *ifp);
void pim_if_addr_del_all_igmp(struct interface *ifp); void pim_if_addr_del_all_igmp(struct interface *ifp);
void pim_if_addr_del_all_pim(struct interface *ifp); void pim_if_addr_del_all_pim(struct interface *ifp);
struct interface *pim_if_lookup_address_vrf (struct in_addr src, vrf_id_t vrf_id);
int pim_if_add_vif(struct interface *ifp); int pim_if_add_vif(struct interface *ifp);
int pim_if_del_vif(struct interface *ifp); int pim_if_del_vif(struct interface *ifp);
void pim_if_add_vif_all(void); void pim_if_add_vif_all(void);
@ -166,4 +184,8 @@ void pim_if_update_join_desired(struct pim_interface *pim_ifp);
void pim_if_update_assert_tracking_desired(struct interface *ifp); void pim_if_update_assert_tracking_desired(struct interface *ifp);
void pim_if_create_pimreg(void); void pim_if_create_pimreg(void);
int pim_if_connected_to_source (struct interface *ifp, struct in_addr src);
int pim_update_source_set(struct interface *ifp, struct in_addr source);
#endif /* PIM_IFACE_H */ #endif /* PIM_IFACE_H */

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,7 @@
#include <zebra.h> #include <zebra.h>
#include "if.h" #include "if.h"
#include "prefix.h"
#include "pim_upstream.h" #include "pim_upstream.h"
@ -35,7 +36,10 @@ enum pim_ifmembership {
enum pim_ifjoin_state { enum pim_ifjoin_state {
PIM_IFJOIN_NOINFO, PIM_IFJOIN_NOINFO,
PIM_IFJOIN_JOIN, PIM_IFJOIN_JOIN,
PIM_IFJOIN_PRUNE_PENDING PIM_IFJOIN_PRUNE,
PIM_IFJOIN_PRUNE_PENDING,
PIM_IFJOIN_PRUNE_TMP,
PIM_IFJOIN_PRUNE_PENDING_TMP,
}; };
enum pim_ifassert_state { enum pim_ifassert_state {
@ -66,12 +70,22 @@ struct pim_assert_metric {
#define PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(flags) ((flags) |= PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED) #define PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(flags) ((flags) |= PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED)
#define PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(flags) ((flags) &= ~PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED) #define PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(flags) ((flags) &= ~PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED)
/*
* Flat to tell us if the ifchannel is (S,G,rpt)
*/
#define PIM_IF_FLAG_MASK_S_G_RPT (1 << 2)
#define PIM_IF_FLAG_TEST_S_G_RPT(flags) ((flags) & PIM_IF_FLAG_MASK_S_G_RPT)
#define PIM_IF_FLAG_SET_S_G_RPT(flags) ((flags) |= PIM_IF_FLAG_MASK_S_G_RPT)
#define PIM_IF_FLAG_UNSET_S_G_RPT(flags) ((flags) &= ~PIM_IF_FLAG_MASK_S_G_RPT)
/* /*
Per-interface (S,G) state Per-interface (S,G) state
*/ */
struct pim_ifchannel { struct pim_ifchannel {
struct in_addr source_addr; /* (S,G) source key */ struct pim_ifchannel *parent;
struct in_addr group_addr; /* (S,G) group key */ struct list *sources;
struct prefix_sg sg;
char sg_str[PIM_SG_LEN];
struct interface *interface; /* backpointer to interface */ struct interface *interface; /* backpointer to interface */
uint32_t flags; uint32_t flags;
@ -98,33 +112,28 @@ struct pim_ifchannel {
void pim_ifchannel_free(struct pim_ifchannel *ch); void pim_ifchannel_free(struct pim_ifchannel *ch);
void pim_ifchannel_delete(struct pim_ifchannel *ch); void pim_ifchannel_delete(struct pim_ifchannel *ch);
void pim_ifchannel_delete_all (struct interface *ifp);
void pim_ifchannel_membership_clear(struct interface *ifp); void pim_ifchannel_membership_clear(struct interface *ifp);
void pim_ifchannel_delete_on_noinfo(struct interface *ifp); void pim_ifchannel_delete_on_noinfo(struct interface *ifp);
struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp,
struct in_addr source_addr, struct prefix_sg *sg);
struct in_addr group_addr);
struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
struct in_addr source_addr, struct prefix_sg *sg, int flags);
struct in_addr group_addr);
void pim_ifchannel_join_add(struct interface *ifp, void pim_ifchannel_join_add(struct interface *ifp,
struct in_addr neigh_addr, struct in_addr neigh_addr,
struct in_addr upstream, struct in_addr upstream,
struct in_addr source_addr, struct prefix_sg *sg,
struct in_addr group_addr,
uint8_t source_flags, uint8_t source_flags,
uint16_t holdtime); uint16_t holdtime);
void pim_ifchannel_prune(struct interface *ifp, void pim_ifchannel_prune(struct interface *ifp,
struct in_addr upstream, struct in_addr upstream,
struct in_addr source_addr, struct prefix_sg *sg,
struct in_addr group_addr,
uint8_t source_flags, uint8_t source_flags,
uint16_t holdtime); uint16_t holdtime);
void pim_ifchannel_local_membership_add(struct interface *ifp, void pim_ifchannel_local_membership_add(struct interface *ifp,
struct in_addr source_addr, struct prefix_sg *sg);
struct in_addr group_addr);
void pim_ifchannel_local_membership_del(struct interface *ifp, void pim_ifchannel_local_membership_del(struct interface *ifp,
struct in_addr source_addr, struct prefix_sg *sg);
struct in_addr group_addr);
void pim_ifchannel_ifjoin_switch(const char *caller, void pim_ifchannel_ifjoin_switch(const char *caller,
struct pim_ifchannel *ch, struct pim_ifchannel *ch,
@ -140,4 +149,8 @@ void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch);
void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch); void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch);
void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch); void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch);
void pim_ifchannel_scan_forward_start (struct interface *new_ifp);
void pim_ifchannel_set_star_g_join_state (struct pim_ifchannel *ch, int eom);
int pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2);
#endif /* PIM_IFCHANNEL_H */ #endif /* PIM_IFCHANNEL_H */

File diff suppressed because it is too large Load Diff

View File

@ -51,6 +51,7 @@
#define IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET (2) #define IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET (2)
#define IGMP_V3_GROUP_RECORD_GROUP_OFFSET (4) #define IGMP_V3_GROUP_RECORD_GROUP_OFFSET (4)
#define IGMP_V3_GROUP_RECORD_SOURCE_OFFSET (8) #define IGMP_V3_GROUP_RECORD_SOURCE_OFFSET (8)
#define IGMP_CHECKSUM_OFFSET (2)
/* RFC 3376: 8.1. Robustness Variable - Default: 2 */ /* RFC 3376: 8.1. Robustness Variable - Default: 2 */
#define IGMP_DEFAULT_ROBUSTNESS_VARIABLE (2) #define IGMP_DEFAULT_ROBUSTNESS_VARIABLE (2)
@ -64,6 +65,8 @@
/* RFC 3376: 8.8. Last Member Query Interval - Default: 10 deciseconds */ /* RFC 3376: 8.8. Last Member Query Interval - Default: 10 deciseconds */
#define IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC (10) #define IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC (10)
#define IGMP_DEFAULT_VERSION (3)
struct igmp_join { struct igmp_join {
struct in_addr group_addr; struct in_addr group_addr;
struct in_addr source_addr; struct in_addr source_addr;
@ -97,7 +100,7 @@ struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list,
struct interface *ifp); struct interface *ifp);
void igmp_sock_delete(struct igmp_sock *igmp); void igmp_sock_delete(struct igmp_sock *igmp);
void igmp_sock_free(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); int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len);
void pim_igmp_general_query_on(struct igmp_sock *igmp); void pim_igmp_general_query_on(struct igmp_sock *igmp);
@ -151,6 +154,9 @@ struct igmp_group {
since sources have their counters) */ since sources have their counters) */
int group_specific_query_retransmit_count; int group_specific_query_retransmit_count;
/* compatibility mode - igmp v1, v2 or v3 */
int igmp_version;
struct in_addr group_addr; struct in_addr group_addr;
int group_filtermode_isexcl; /* 0=INCLUDE, 1=EXCLUDE */ int group_filtermode_isexcl; /* 0=INCLUDE, 1=EXCLUDE */
struct list *group_source_list; /* list of struct igmp_source */ struct list *group_source_list; /* list of struct igmp_source */
@ -175,4 +181,18 @@ void igmp_group_timer_on(struct igmp_group *group,
struct igmp_source * struct igmp_source *
source_new (struct igmp_group *group, source_new (struct igmp_group *group,
struct in_addr src_addr); struct in_addr src_addr);
void igmp_send_query(int igmp_version,
struct igmp_group *group,
int fd,
const char *ifname,
char *query_buf,
int query_buf_size,
int num_sources,
struct in_addr dst_addr,
struct in_addr group_addr,
int query_max_response_time_dsec,
uint8_t s_flag,
uint8_t querier_robustness_variable,
uint16_t querier_query_interval);
#endif /* PIM_IGMP_H */ #endif /* PIM_IGMP_H */

190
pimd/pim_igmpv2.c Normal file
View File

@ -0,0 +1,190 @@
/*
* PIM for Quagga
* Copyright (C) 2016 Cumulus Networks, Inc.
* Daniel Walton
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "zebra.h"
#include "pimd.h"
#include "pim_igmp.h"
#include "pim_igmpv2.h"
#include "pim_igmpv3.h"
#include "pim_str.h"
#include "pim_time.h"
#include "pim_util.h"
static void
on_trace (const char *label,
struct interface *ifp, struct in_addr from)
{
if (PIM_DEBUG_IGMP_TRACE) {
char from_str[INET_ADDRSTRLEN];
pim_inet4_dump("<from?>", from, from_str, sizeof(from_str));
zlog_debug("%s: from %s on %s",
label, from_str, ifp->name);
}
}
void
igmp_v2_send_query (struct igmp_group *group,
int fd,
const char *ifname,
char *query_buf,
struct in_addr dst_addr,
struct in_addr group_addr,
int query_max_response_time_dsec)
{
ssize_t msg_size = 8;
uint8_t max_resp_code;
ssize_t sent;
struct sockaddr_in to;
socklen_t tolen;
uint16_t checksum;
/* max_resp_code must be non-zero else this will look like an IGMP v1 query */
max_resp_code = igmp_msg_encode16to8(query_max_response_time_dsec);
zassert(max_resp_code > 0);
query_buf[0] = PIM_IGMP_MEMBERSHIP_QUERY;
query_buf[1] = max_resp_code;
*(uint16_t *)(query_buf + IGMP_CHECKSUM_OFFSET) = 0; /* for computing checksum */
memcpy(query_buf+4, &group_addr, sizeof(struct in_addr));
checksum = in_cksum(query_buf, msg_size);
*(uint16_t *)(query_buf + IGMP_CHECKSUM_OFFSET) = checksum;
if (PIM_DEBUG_IGMP_PACKETS) {
char dst_str[INET_ADDRSTRLEN];
char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
zlog_debug("Send IGMPv2 QUERY to %s on %s for group %s",
dst_str, ifname, group_str);
}
memset(&to, 0, sizeof(to));
to.sin_family = AF_INET;
to.sin_addr = dst_addr;
tolen = sizeof(to);
sent = sendto(fd, query_buf, msg_size, MSG_DONTWAIT,
(struct sockaddr *)&to, tolen);
if (sent != (ssize_t) msg_size) {
char dst_str[INET_ADDRSTRLEN];
char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
if (sent < 0) {
zlog_warn("Send IGMPv2 QUERY failed due to %s on %s: group=%s msg_size=%zd: errno=%d: %s",
dst_str, ifname, group_str, msg_size, errno, safe_strerror(errno));
}
else {
zlog_warn("Send IGMPv2 QUERY failed due to %s on %s: group=%s msg_size=%zd: sent=%zd",
dst_str, ifname, group_str, msg_size, sent);
}
return;
}
}
int
igmp_v2_recv_report (struct igmp_sock *igmp,
struct in_addr from, const char *from_str,
char *igmp_msg, int igmp_msg_len)
{
struct interface *ifp = igmp->interface;
struct in_addr group_addr;
char group_str[INET_ADDRSTRLEN];
on_trace(__PRETTY_FUNCTION__, igmp->interface, from);
if (igmp_msg_len != IGMP_V12_MSG_SIZE) {
zlog_warn("Recv IGMPv2 REPORT from %s on %s: size=%d other than correct=%d",
from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE);
return -1;
}
memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
if (PIM_DEBUG_IGMP_PACKETS) {
pim_inet4_dump("<dst?>", group_addr, group_str, sizeof(group_str));
zlog_debug("Recv IGMPv2 REPORT from %s on %s for %s",
from_str, ifp->name, group_str);
}
/*
* RFC 3376
* 7.3.2. In the Presence of Older Version Group Members
*
* When Group Compatibility Mode is IGMPv2, a router internally
* translates the following IGMPv2 messages for that group to their
* IGMPv3 equivalents:
*
* IGMPv2 Message IGMPv3 Equivalent
* -------------- -----------------
* Report IS_EX( {} )
* Leave TO_IN( {} )
*/
igmpv3_report_isex (igmp, from, group_addr, 0, NULL, 1);
return 0;
}
int
igmp_v2_recv_leave (struct igmp_sock *igmp,
struct in_addr from, const char *from_str,
char *igmp_msg, int igmp_msg_len)
{
struct interface *ifp = igmp->interface;
struct in_addr group_addr;
char group_str[INET_ADDRSTRLEN];
on_trace(__PRETTY_FUNCTION__, igmp->interface, from);
if (igmp_msg_len != IGMP_V12_MSG_SIZE) {
zlog_warn("Recv IGMPv2 LEAVE from %s on %s: size=%d other than correct=%d",
from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE);
return -1;
}
memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
if (PIM_DEBUG_IGMP_PACKETS) {
pim_inet4_dump("<dst?>", group_addr, group_str, sizeof(group_str));
zlog_debug("Recv IGMPv2 LEAVE from %s on %s for %s",
from_str, ifp->name, group_str);
}
/*
* RFC 3376
* 7.3.2. In the Presence of Older Version Group Members
*
* When Group Compatibility Mode is IGMPv2, a router internally
* translates the following IGMPv2 messages for that group to their
* IGMPv3 equivalents:
*
* IGMPv2 Message IGMPv3 Equivalent
* -------------- -----------------
* Report IS_EX( {} )
* Leave TO_IN( {} )
*/
igmpv3_report_toin (igmp, from, group_addr, 0, NULL);
return 0;
}

41
pimd/pim_igmpv2.h Normal file
View File

@ -0,0 +1,41 @@
/*
* PIM for Quagga
* Copyright (C) 2016 Cumulus Networks, Inc.
* Daniel Walton
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifndef PIM_IGMPV2_H
#define PIM_IGMPV2_H
void igmp_v2_send_query (struct igmp_group *group,
int fd,
const char *ifname,
char *query_buf,
struct in_addr dst_addr,
struct in_addr group_addr,
int query_max_response_time_dsec);
int igmp_v2_recv_report (struct igmp_sock *igmp,
struct in_addr from, const char *from_str,
char *igmp_msg, int igmp_msg_len);
int igmp_v2_recv_leave (struct igmp_sock *igmp,
struct in_addr from, const char *from_str,
char *igmp_msg, int igmp_msg_len);
#endif /* PIM_IGMPV2_H */

View File

@ -46,8 +46,8 @@ static void on_trace(const char *label,
int num_sources, struct in_addr *sources) int num_sources, struct in_addr *sources)
{ {
if (PIM_DEBUG_IGMP_TRACE) { if (PIM_DEBUG_IGMP_TRACE) {
char from_str[100]; char from_str[INET_ADDRSTRLEN];
char group_str[100]; char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<from?>", from, from_str, sizeof(from_str)); pim_inet4_dump("<from?>", from, from_str, sizeof(from_str));
pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
@ -57,50 +57,6 @@ static void on_trace(const char *label,
} }
} }
int igmp_group_compat_mode(const struct igmp_sock *igmp,
const struct igmp_group *group)
{
struct pim_interface *pim_ifp;
int64_t now_dsec;
long older_host_present_interval_dsec;
zassert(igmp);
zassert(igmp->interface);
zassert(igmp->interface->info);
pim_ifp = igmp->interface->info;
/*
RFC 3376: 8.13. Older Host Present Interval
This value MUST be ((the Robustness Variable) times (the Query
Interval)) plus (one Query Response Interval).
older_host_present_interval_dsec = \
igmp->querier_robustness_variable * \
10 * igmp->querier_query_interval + \
pim_ifp->query_max_response_time_dsec;
*/
older_host_present_interval_dsec =
PIM_IGMP_OHPI_DSEC(igmp->querier_robustness_variable,
igmp->querier_query_interval,
pim_ifp->igmp_query_max_response_time_dsec);
now_dsec = pim_time_monotonic_dsec();
if (now_dsec < 1) {
/* broken timer logged by pim_time_monotonic_dsec() */
return 3;
}
if ((now_dsec - group->last_igmp_v1_report_dsec) < older_host_present_interval_dsec)
return 1; /* IGMPv1 */
if ((now_dsec - group->last_igmp_v2_report_dsec) < older_host_present_interval_dsec)
return 2; /* IGMPv2 */
return 3; /* IGMPv3 */
}
void igmp_group_reset_gmi(struct igmp_group *group) void igmp_group_reset_gmi(struct igmp_group *group)
{ {
long group_membership_interval_msec; long group_membership_interval_msec;
@ -132,7 +88,7 @@ void igmp_group_reset_gmi(struct igmp_group *group)
pim_ifp->igmp_query_max_response_time_dsec); pim_ifp->igmp_query_max_response_time_dsec);
if (PIM_DEBUG_IGMP_TRACE) { if (PIM_DEBUG_IGMP_TRACE) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_debug("Resetting group %s timer to GMI=%ld.%03ld sec on %s", zlog_debug("Resetting group %s timer to GMI=%ld.%03ld sec on %s",
group_str, group_str,
@ -158,15 +114,13 @@ static int igmp_source_timer(struct thread *t)
struct igmp_source *source; struct igmp_source *source;
struct igmp_group *group; struct igmp_group *group;
zassert(t);
source = THREAD_ARG(t); source = THREAD_ARG(t);
zassert(source);
group = source->source_group; group = source->source_group;
if (PIM_DEBUG_IGMP_TRACE) { if (PIM_DEBUG_IGMP_TRACE) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
zlog_debug("%s: Source timer expired for group %s source %s on %s", zlog_debug("%s: Source timer expired for group %s source %s on %s",
@ -176,7 +130,7 @@ static int igmp_source_timer(struct thread *t)
} }
zassert(source->t_source_timer); zassert(source->t_source_timer);
source->t_source_timer = 0; source->t_source_timer = NULL;
/* /*
RFC 3376: 6.3. IGMPv3 Source-Specific Forwarding Rules RFC 3376: 6.3. IGMPv3 Source-Specific Forwarding Rules
@ -230,8 +184,8 @@ static void source_timer_off(struct igmp_group *group,
return; return;
if (PIM_DEBUG_IGMP_TRACE) { if (PIM_DEBUG_IGMP_TRACE) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
zlog_debug("Cancelling TIMER event for group %s source %s on %s", zlog_debug("Cancelling TIMER event for group %s source %s on %s",
@ -250,8 +204,8 @@ static void igmp_source_timer_on(struct igmp_group *group,
source_timer_off(group, source); source_timer_off(group, source);
if (PIM_DEBUG_IGMP_EVENTS) { if (PIM_DEBUG_IGMP_EVENTS) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
zlog_debug("Scheduling %ld.%03ld sec TIMER event for group %s source %s on %s", zlog_debug("Scheduling %ld.%03ld sec TIMER event for group %s source %s on %s",
@ -291,8 +245,8 @@ void igmp_source_reset_gmi(struct igmp_sock *igmp,
pim_ifp->igmp_query_max_response_time_dsec); pim_ifp->igmp_query_max_response_time_dsec);
if (PIM_DEBUG_IGMP_TRACE) { if (PIM_DEBUG_IGMP_TRACE) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
@ -383,7 +337,7 @@ static void source_channel_oil_detach(struct igmp_source *source)
{ {
if (source->source_channel_oil) { if (source->source_channel_oil) {
pim_channel_oil_del(source->source_channel_oil); pim_channel_oil_del(source->source_channel_oil);
source->source_channel_oil = 0; source->source_channel_oil = NULL;
} }
} }
@ -398,8 +352,8 @@ void igmp_source_delete(struct igmp_source *source)
group = source->source_group; group = source->source_group;
if (PIM_DEBUG_IGMP_TRACE) { if (PIM_DEBUG_IGMP_TRACE) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
zlog_debug("Deleting IGMP source %s for group %s from socket %d interface %s", zlog_debug("Deleting IGMP source %s for group %s from socket %d interface %s",
@ -413,8 +367,8 @@ void igmp_source_delete(struct igmp_source *source)
/* sanity check that forwarding has been disabled */ /* sanity check that forwarding has been disabled */
if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) { if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
zlog_warn("%s: forwarding=ON(!) IGMP source %s for group %s from socket %d interface %s", zlog_warn("%s: forwarding=ON(!) IGMP source %s for group %s from socket %d interface %s",
@ -483,8 +437,8 @@ source_new (struct igmp_group *group,
struct igmp_source *src; struct igmp_source *src;
if (PIM_DEBUG_IGMP_TRACE) { if (PIM_DEBUG_IGMP_TRACE) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", src_addr, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", src_addr, source_str, sizeof(source_str));
zlog_debug("Creating new IGMP source %s for group %s on socket %d interface %s", zlog_debug("Creating new IGMP source %s for group %s on socket %d interface %s",
@ -493,9 +447,9 @@ source_new (struct igmp_group *group,
group->group_igmp_sock->interface->name); group->group_igmp_sock->interface->name);
} }
src = XMALLOC(MTYPE_PIM_IGMP_GROUP_SOURCE, sizeof(*src)); src = XCALLOC(MTYPE_PIM_IGMP_GROUP_SOURCE, sizeof(*src));
if (!src) { if (!src) {
zlog_warn("%s %s: XMALLOC() failure", zlog_warn("%s %s: XCALLOC() failure",
__FILE__, __PRETTY_FUNCTION__); __FILE__, __PRETTY_FUNCTION__);
return 0; /* error, not found, could not create */ return 0; /* error, not found, could not create */
} }
@ -646,8 +600,10 @@ static void isex_excl(struct igmp_group *group,
struct in_addr star = { .s_addr = INADDR_ANY }; struct in_addr star = { .s_addr = INADDR_ANY };
source = igmp_find_source_by_addr (group, star); source = igmp_find_source_by_addr (group, star);
if (source) if (source)
IGMP_SOURCE_DONT_DELETE(source->source_flags); {
igmp_source_reset_gmi (group->group_igmp_sock, group, source); IGMP_SOURCE_DONT_DELETE(source->source_flags);
igmp_source_reset_gmi (group->group_igmp_sock, group, source);
}
} }
/* E.5: delete all sources marked with deletion flag: (X-A) and (Y-A) */ /* E.5: delete all sources marked with deletion flag: (X-A) and (Y-A) */
@ -702,7 +658,8 @@ static void isex_incl(struct igmp_group *group,
void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from, void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from,
struct in_addr group_addr, struct in_addr group_addr,
int num_sources, struct in_addr *sources) int num_sources, struct in_addr *sources,
int from_igmp_v2_report)
{ {
struct interface *ifp = igmp->interface; struct interface *ifp = igmp->interface;
struct igmp_group *group; struct igmp_group *group;
@ -716,6 +673,10 @@ void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from,
return; return;
} }
/* So we can display how we learned the group in our show command output */
if (from_igmp_v2_report)
group->igmp_version = 2;
if (group->group_filtermode_isexcl) { if (group->group_filtermode_isexcl) {
/* EXCLUDE mode */ /* EXCLUDE mode */
isex_excl(group, num_sources, sources); isex_excl(group, num_sources, sources);
@ -932,6 +893,16 @@ static void toex_excl(struct igmp_group *group,
/* clear off SEND flag from all known sources (X,Y) */ /* clear off SEND flag from all known sources (X,Y) */
source_clear_send_flag(group->group_source_list); source_clear_send_flag(group->group_source_list);
if (num_sources == 0)
{
struct igmp_source *source;
struct in_addr any = { .s_addr = INADDR_ANY };
source = igmp_find_source_by_addr (group, any);
if (source)
IGMP_SOURCE_DONT_DELETE(source->source_flags);
}
/* scan received sources (A) */ /* scan received sources (A) */
for (i = 0; i < num_sources; ++i) { for (i = 0; i < num_sources; ++i) {
struct igmp_source *source; struct igmp_source *source;
@ -1037,17 +1008,25 @@ void igmpv3_report_allow(struct igmp_sock *igmp, struct in_addr from,
*/ */
static void group_retransmit_group(struct igmp_group *group) static void group_retransmit_group(struct igmp_group *group)
{ {
char query_buf[PIM_IGMP_BUFSIZE_WRITE];
struct igmp_sock *igmp; struct igmp_sock *igmp;
struct pim_interface *pim_ifp; struct pim_interface *pim_ifp;
long lmqc; /* Last Member Query Count */ long lmqc; /* Last Member Query Count */
long lmqi_msec; /* Last Member Query Interval */ long lmqi_msec; /* Last Member Query Interval */
long lmqt_msec; /* Last Member Query Time */ long lmqt_msec; /* Last Member Query Time */
int s_flag; int s_flag;
int query_buf_size;
igmp = group->group_igmp_sock; igmp = group->group_igmp_sock;
pim_ifp = igmp->interface->info; pim_ifp = igmp->interface->info;
if (pim_ifp->igmp_version == 3) {
query_buf_size = PIM_IGMP_BUFSIZE_WRITE;
} else {
query_buf_size = IGMP_V12_MSG_SIZE;
}
char query_buf[query_buf_size];
lmqc = igmp->querier_robustness_variable; lmqc = igmp->querier_robustness_variable;
lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec; lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec;
lmqt_msec = lmqc * lmqi_msec; lmqt_msec = lmqc * lmqi_msec;
@ -1062,7 +1041,7 @@ static void group_retransmit_group(struct igmp_group *group)
s_flag = igmp_group_timer_remain_msec(group) > lmqt_msec; s_flag = igmp_group_timer_remain_msec(group) > lmqt_msec;
if (PIM_DEBUG_IGMP_TRACE) { if (PIM_DEBUG_IGMP_TRACE) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_debug("retransmit_group_specific_query: group %s on %s: s_flag=%d count=%d", zlog_debug("retransmit_group_specific_query: group %s on %s: s_flag=%d count=%d",
group_str, igmp->interface->name, s_flag, group_str, igmp->interface->name, s_flag,
@ -1077,18 +1056,19 @@ static void group_retransmit_group(struct igmp_group *group)
interest. interest.
*/ */
pim_igmp_send_membership_query(group, igmp_send_query(pim_ifp->igmp_version,
igmp->fd, group,
igmp->interface->name, igmp->fd,
query_buf, igmp->interface->name,
sizeof(query_buf), query_buf,
0 /* num_sources_tosend */, sizeof(query_buf),
group->group_addr /* dst_addr */, 0 /* num_sources_tosend */,
group->group_addr /* group_addr */, group->group_addr /* dst_addr */,
pim_ifp->igmp_specific_query_max_response_time_dsec, group->group_addr /* group_addr */,
s_flag, pim_ifp->igmp_specific_query_max_response_time_dsec,
igmp->querier_robustness_variable, s_flag,
igmp->querier_query_interval); igmp->querier_robustness_variable,
igmp->querier_query_interval);
} }
/* /*
@ -1123,9 +1103,6 @@ static int group_retransmit_sources(struct igmp_group *group,
struct igmp_source *src; struct igmp_source *src;
int num_retransmit_sources_left = 0; int num_retransmit_sources_left = 0;
query_buf1_max_sources = (sizeof(query_buf1) - IGMP_V3_SOURCES_OFFSET) >> 2;
query_buf2_max_sources = (sizeof(query_buf2) - IGMP_V3_SOURCES_OFFSET) >> 2;
source_addr1 = (struct in_addr *)(query_buf1 + IGMP_V3_SOURCES_OFFSET); source_addr1 = (struct in_addr *)(query_buf1 + IGMP_V3_SOURCES_OFFSET);
source_addr2 = (struct in_addr *)(query_buf2 + IGMP_V3_SOURCES_OFFSET); source_addr2 = (struct in_addr *)(query_buf2 + IGMP_V3_SOURCES_OFFSET);
@ -1163,7 +1140,7 @@ static int group_retransmit_sources(struct igmp_group *group,
num_sources_tosend2 = source_addr2 - (struct in_addr *)(query_buf2 + IGMP_V3_SOURCES_OFFSET); num_sources_tosend2 = source_addr2 - (struct in_addr *)(query_buf2 + IGMP_V3_SOURCES_OFFSET);
if (PIM_DEBUG_IGMP_TRACE) { if (PIM_DEBUG_IGMP_TRACE) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_debug("retransmit_grp&src_specific_query: group %s on %s: srcs_with_sflag=%d srcs_wo_sflag=%d will_send_sflag=%d retransmit_src_left=%d", zlog_debug("retransmit_grp&src_specific_query: group %s on %s: srcs_with_sflag=%d srcs_wo_sflag=%d will_send_sflag=%d retransmit_src_left=%d",
group_str, igmp->interface->name, group_str, igmp->interface->name,
@ -1183,7 +1160,7 @@ static int group_retransmit_sources(struct igmp_group *group,
query_buf1_max_sources = (sizeof(query_buf1) - IGMP_V3_SOURCES_OFFSET) >> 2; query_buf1_max_sources = (sizeof(query_buf1) - IGMP_V3_SOURCES_OFFSET) >> 2;
if (num_sources_tosend1 > query_buf1_max_sources) { if (num_sources_tosend1 > query_buf1_max_sources) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_warn("%s: group %s on %s: s_flag=1 unable to fit %d sources into buf_size=%zu (max_sources=%d)", zlog_warn("%s: group %s on %s: s_flag=1 unable to fit %d sources into buf_size=%zu (max_sources=%d)",
__PRETTY_FUNCTION__, group_str, igmp->interface->name, __PRETTY_FUNCTION__, group_str, igmp->interface->name,
@ -1198,19 +1175,19 @@ static int group_retransmit_sources(struct igmp_group *group,
interest. interest.
*/ */
pim_igmp_send_membership_query(group, igmp_send_query(pim_ifp->igmp_version,
igmp->fd, group,
igmp->interface->name, igmp->fd,
query_buf1, igmp->interface->name,
sizeof(query_buf1), query_buf1,
num_sources_tosend1, sizeof(query_buf1),
group->group_addr, num_sources_tosend1,
group->group_addr, group->group_addr,
pim_ifp->igmp_specific_query_max_response_time_dsec, group->group_addr,
1 /* s_flag */, pim_ifp->igmp_specific_query_max_response_time_dsec,
igmp->querier_robustness_variable, 1 /* s_flag */,
igmp->querier_query_interval); igmp->querier_robustness_variable,
igmp->querier_query_interval);
} }
} /* send_with_sflag_set */ } /* send_with_sflag_set */
@ -1225,7 +1202,7 @@ static int group_retransmit_sources(struct igmp_group *group,
query_buf2_max_sources = (sizeof(query_buf2) - IGMP_V3_SOURCES_OFFSET) >> 2; query_buf2_max_sources = (sizeof(query_buf2) - IGMP_V3_SOURCES_OFFSET) >> 2;
if (num_sources_tosend2 > query_buf2_max_sources) { if (num_sources_tosend2 > query_buf2_max_sources) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_warn("%s: group %s on %s: s_flag=0 unable to fit %d sources into buf_size=%zu (max_sources=%d)", zlog_warn("%s: group %s on %s: s_flag=0 unable to fit %d sources into buf_size=%zu (max_sources=%d)",
__PRETTY_FUNCTION__, group_str, igmp->interface->name, __PRETTY_FUNCTION__, group_str, igmp->interface->name,
@ -1240,19 +1217,19 @@ static int group_retransmit_sources(struct igmp_group *group,
interest. interest.
*/ */
pim_igmp_send_membership_query(group, igmp_send_query(pim_ifp->igmp_version,
igmp->fd, group,
igmp->interface->name, igmp->fd,
query_buf2, igmp->interface->name,
sizeof(query_buf2), query_buf2,
num_sources_tosend2, sizeof(query_buf2),
group->group_addr, num_sources_tosend2,
group->group_addr, group->group_addr,
pim_ifp->igmp_specific_query_max_response_time_dsec, group->group_addr,
0 /* s_flag */, pim_ifp->igmp_specific_query_max_response_time_dsec,
igmp->querier_robustness_variable, 0 /* s_flag */,
igmp->querier_query_interval); igmp->querier_robustness_variable,
igmp->querier_query_interval);
} }
} }
@ -1265,12 +1242,10 @@ static int igmp_group_retransmit(struct thread *t)
int num_retransmit_sources_left; int num_retransmit_sources_left;
int send_with_sflag_set; /* boolean */ int send_with_sflag_set; /* boolean */
zassert(t);
group = THREAD_ARG(t); group = THREAD_ARG(t);
zassert(group);
if (PIM_DEBUG_IGMP_TRACE) { if (PIM_DEBUG_IGMP_TRACE) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_debug("group_retransmit_timer: group %s on %s", zlog_debug("group_retransmit_timer: group %s on %s",
group_str, group->group_igmp_sock->interface->name); group_str, group->group_igmp_sock->interface->name);
@ -1300,7 +1275,7 @@ static int igmp_group_retransmit(struct thread *t)
num_retransmit_sources_left = group_retransmit_sources(group, num_retransmit_sources_left = group_retransmit_sources(group,
send_with_sflag_set); send_with_sflag_set);
group->t_group_query_retransmit_timer = 0; group->t_group_query_retransmit_timer = NULL;
/* /*
Keep group retransmit timer running if there is any retransmit Keep group retransmit timer running if there is any retransmit
@ -1336,7 +1311,7 @@ static void group_retransmit_timer_on(struct igmp_group *group)
lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec; lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec;
if (PIM_DEBUG_IGMP_TRACE) { if (PIM_DEBUG_IGMP_TRACE) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_debug("Scheduling %ld.%03ld sec retransmit timer for group %s on %s", zlog_debug("Scheduling %ld.%03ld sec retransmit timer for group %s on %s",
lmqi_msec / 1000, lmqi_msec / 1000,
@ -1565,7 +1540,7 @@ void igmp_group_timer_lower_to_lmqt(struct igmp_group *group)
lmqt_msec = PIM_IGMP_LMQT_MSEC(lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */ lmqt_msec = PIM_IGMP_LMQT_MSEC(lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */
if (PIM_DEBUG_IGMP_TRACE) { if (PIM_DEBUG_IGMP_TRACE) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_debug("%s: group %s on %s: LMQC=%d LMQI=%d dsec LMQT=%d msec", zlog_debug("%s: group %s on %s: LMQC=%d LMQI=%d dsec LMQT=%d msec",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -1600,8 +1575,8 @@ void igmp_source_timer_lower_to_lmqt(struct igmp_source *source)
lmqt_msec = PIM_IGMP_LMQT_MSEC(lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */ lmqt_msec = PIM_IGMP_LMQT_MSEC(lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */
if (PIM_DEBUG_IGMP_TRACE) { if (PIM_DEBUG_IGMP_TRACE) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
zlog_debug("%s: group %s source %s on %s: LMQC=%d LMQI=%d dsec LMQT=%d msec", zlog_debug("%s: group %s source %s on %s: LMQC=%d LMQI=%d dsec LMQT=%d msec",
@ -1613,32 +1588,19 @@ void igmp_source_timer_lower_to_lmqt(struct igmp_source *source)
igmp_source_timer_on(group, source, lmqt_msec); igmp_source_timer_on(group, source, lmqt_msec);
} }
/* void
Copy sources to message: igmp_v3_send_query (struct igmp_group *group,
int fd,
struct in_addr *sources = (struct in_addr *)(query_buf + IGMP_V3_SOURCES_OFFSET); const char *ifname,
if (num_sources > 0) { char *query_buf,
struct listnode *node; int query_buf_size,
struct igmp_source *src; int num_sources,
int i = 0; struct in_addr dst_addr,
struct in_addr group_addr,
for (ALL_LIST_ELEMENTS_RO(source_list, node, src)) { int query_max_response_time_dsec,
sources[i++] = src->source_addr; uint8_t s_flag,
} uint8_t querier_robustness_variable,
} uint16_t querier_query_interval)
*/
void pim_igmp_send_membership_query(struct igmp_group *group,
int fd,
const char *ifname,
char *query_buf,
int query_buf_size,
int num_sources,
struct in_addr dst_addr,
struct in_addr group_addr,
int query_max_response_time_dsec,
uint8_t s_flag,
uint8_t querier_robustness_variable,
uint16_t querier_query_interval)
{ {
ssize_t msg_size; ssize_t msg_size;
uint8_t max_resp_code; uint8_t max_resp_code;
@ -1678,7 +1640,7 @@ void pim_igmp_send_membership_query(struct igmp_group *group,
query_buf[0] = PIM_IGMP_MEMBERSHIP_QUERY; query_buf[0] = PIM_IGMP_MEMBERSHIP_QUERY;
query_buf[1] = max_resp_code; query_buf[1] = max_resp_code;
*(uint16_t *)(query_buf + IGMP_V3_CHECKSUM_OFFSET) = 0; /* for computing checksum */ *(uint16_t *)(query_buf + IGMP_CHECKSUM_OFFSET) = 0; /* for computing checksum */
memcpy(query_buf+4, &group_addr, sizeof(struct in_addr)); memcpy(query_buf+4, &group_addr, sizeof(struct in_addr));
query_buf[8] = (s_flag << 3) | querier_robustness_variable; query_buf[8] = (s_flag << 3) | querier_robustness_variable;
@ -1686,18 +1648,17 @@ void pim_igmp_send_membership_query(struct igmp_group *group,
*(uint16_t *)(query_buf + IGMP_V3_NUMSOURCES_OFFSET) = htons(num_sources); *(uint16_t *)(query_buf + IGMP_V3_NUMSOURCES_OFFSET) = htons(num_sources);
checksum = in_cksum(query_buf, msg_size); checksum = in_cksum(query_buf, msg_size);
*(uint16_t *)(query_buf + IGMP_V3_CHECKSUM_OFFSET) = checksum; *(uint16_t *)(query_buf + IGMP_CHECKSUM_OFFSET) = checksum;
if (PIM_DEBUG_IGMP_PACKETS) { if (PIM_DEBUG_IGMP_PACKETS) {
char dst_str[100]; char dst_str[INET_ADDRSTRLEN];
char group_str[100]; char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str)); pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
zlog_debug("%s: to %s on %s: group=%s sources=%d msg_size=%zd s_flag=%x QRV=%u QQI=%u QQIC=%02x checksum=%x", zlog_debug("Send IGMPv3 query to %s on %s for group %s, sources=%d msg_size=%zd s_flag=%x QRV=%u QQI=%u QQIC=%02x",
__PRETTY_FUNCTION__, dst_str, ifname, group_str,
dst_str, ifname, group_str, num_sources, num_sources, msg_size, s_flag, querier_robustness_variable,
msg_size, s_flag, querier_robustness_variable, querier_query_interval, qqic);
querier_query_interval, qqic, checksum);
} }
memset(&to, 0, sizeof(to)); memset(&to, 0, sizeof(to));
@ -1708,22 +1669,17 @@ void pim_igmp_send_membership_query(struct igmp_group *group,
sent = sendto(fd, query_buf, msg_size, MSG_DONTWAIT, sent = sendto(fd, query_buf, msg_size, MSG_DONTWAIT,
(struct sockaddr *)&to, tolen); (struct sockaddr *)&to, tolen);
if (sent != (ssize_t) msg_size) { if (sent != (ssize_t) msg_size) {
int e = errno; char dst_str[INET_ADDRSTRLEN];
char dst_str[100]; char group_str[INET_ADDRSTRLEN];
char group_str[100];
pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str)); pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
if (sent < 0) { if (sent < 0) {
zlog_warn("%s: sendto() failure to %s on %s: group=%s msg_size=%zd: errno=%d: %s", zlog_warn("Send IGMPv3 query failed due to %s on %s: group=%s msg_size=%zd: errno=%d: %s",
__PRETTY_FUNCTION__, dst_str, ifname, group_str, msg_size, errno, safe_strerror(errno));
dst_str, ifname, group_str, msg_size,
e, safe_strerror(e));
} }
else { else {
zlog_warn("%s: sendto() partial to %s on %s: group=%s msg_size=%zd: sent=%zd", zlog_warn("Send IGMPv3 query failed due to %s on %s: group=%s msg_size=%zd: sent=%zd",
__PRETTY_FUNCTION__, dst_str, ifname, group_str, msg_size, sent);
dst_str, ifname, group_str,
msg_size, sent);
} }
return; return;
} }
@ -1742,8 +1698,8 @@ void pim_igmp_send_membership_query(struct igmp_group *group,
if (!s_flag) { if (!s_flag) {
/* general query? */ /* general query? */
if (PIM_INADDR_IS_ANY(group_addr)) { if (PIM_INADDR_IS_ANY(group_addr)) {
char dst_str[100]; char dst_str[INET_ADDRSTRLEN];
char group_str[100]; char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str)); pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
zlog_warn("%s: to %s on %s: group=%s sources=%d: s_flag is clear for general query!", zlog_warn("%s: to %s on %s: group=%s sources=%d: s_flag is clear for general query!",
@ -1751,5 +1707,268 @@ void pim_igmp_send_membership_query(struct igmp_group *group,
dst_str, ifname, group_str, num_sources); dst_str, ifname, group_str, num_sources);
} }
} }
}
void
igmp_v3_recv_query (struct igmp_sock *igmp, const char *from_str, char *igmp_msg)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
struct in_addr group_addr;
uint8_t resv_s_qrv = 0;
uint8_t s_flag = 0;
uint8_t qrv = 0;
int i;
memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
ifp = igmp->interface;
pim_ifp = ifp->info;
/*
* RFC 3376: 4.1.6. QRV (Querier's Robustness Variable)
*
* Routers adopt the QRV value from the most recently received Query
* as their own [Robustness Variable] value, unless that most
* recently received QRV was zero, in which case the receivers use
* the default [Robustness Variable] value specified in section 8.1
* or a statically configured value.
*/
resv_s_qrv = igmp_msg[8];
qrv = 7 & resv_s_qrv;
igmp->querier_robustness_variable = qrv ? qrv : pim_ifp->igmp_default_robustness_variable;
/*
* RFC 3376: 4.1.7. QQIC (Querier's Query Interval Code)
*
* Multicast routers that are not the current querier adopt the QQI
* value from the most recently received Query as their own [Query
* Interval] value, unless that most recently received QQI was zero,
* in which case the receiving routers use the default.
*/
if (igmp->t_other_querier_timer) {
/* other querier present */
uint8_t qqic;
uint16_t qqi;
qqic = igmp_msg[9];
qqi = igmp_msg_decode8to16(qqic);
igmp->querier_query_interval = qqi ? qqi : pim_ifp->igmp_default_query_interval;
if (PIM_DEBUG_IGMP_TRACE) {
char ifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
zlog_debug("Querier %s new query interval is %s QQI=%u sec (recv QQIC=%02x from %s)",
ifaddr_str,
qqi ? "recv-non-default" : "default",
igmp->querier_query_interval,
qqic,
from_str);
}
}
/*
* RFC 3376: 6.6.1. Timer Updates
*
* When a router sends or receives a query with a clear Suppress
* Router-Side Processing flag, it must update its timers to reflect
* the correct timeout values for the group or sources being queried.
*
* General queries don't trigger timer update.
*/
s_flag = (1 << 3) & resv_s_qrv;
if (!s_flag) {
/* s_flag is clear */
if (PIM_INADDR_IS_ANY(group_addr)) {
/* this is a general query */
/* log that general query should have the s_flag set */
zlog_warn("General IGMP query v3 from %s on %s: Suppress Router-Side Processing flag is clear",
from_str, ifp->name);
} else {
struct igmp_group *group;
/* this is a non-general query: perform timer updates */
group = find_group_by_addr(igmp, group_addr);
if (group) {
int recv_num_sources = ntohs(*(uint16_t *)(igmp_msg + IGMP_V3_NUMSOURCES_OFFSET));
/*
* RFC 3376: 6.6.1. Timer Updates
* Query Q(G,A): Source Timer for sources in A are lowered to LMQT
* Query Q(G): Group Timer is lowered to LMQT
*/
if (recv_num_sources < 1) {
/* Query Q(G): Group Timer is lowered to LMQT */
igmp_group_timer_lower_to_lmqt(group);
} else {
/* Query Q(G,A): Source Timer for sources in A are lowered to LMQT */
/* Scan sources in query and lower their timers to LMQT */
struct in_addr *sources = (struct in_addr *)(igmp_msg + IGMP_V3_SOURCES_OFFSET);
for (i = 0; i < recv_num_sources; ++i) {
struct in_addr src_addr;
struct igmp_source *src;
memcpy(&src_addr, sources + i, sizeof(struct in_addr));
src = igmp_find_source_by_addr(group, src_addr);
if (src) {
igmp_source_timer_lower_to_lmqt(src);
}
}
}
} else {
char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
zlog_warn("IGMP query v3 from %s on %s: could not find group %s for timer update",
from_str, ifp->name, group_str);
}
}
} /* s_flag is clear: timer updates */
}
int
igmp_v3_recv_report (struct igmp_sock *igmp,
struct in_addr from, const char *from_str,
char *igmp_msg, int igmp_msg_len)
{
uint16_t recv_checksum;
uint16_t checksum;
int num_groups;
uint8_t *group_record;
uint8_t *report_pastend = (uint8_t *) igmp_msg + igmp_msg_len;
struct interface *ifp = igmp->interface;
int i;
int local_ncb = 0;
if (igmp_msg_len < IGMP_V3_MSG_MIN_SIZE) {
zlog_warn("Recv IGMP report v3 from %s on %s: size=%d shorter than minimum=%d",
from_str, ifp->name, igmp_msg_len, IGMP_V3_MSG_MIN_SIZE);
return -1;
}
recv_checksum = *(uint16_t *) (igmp_msg + IGMP_CHECKSUM_OFFSET);
/* for computing checksum */
*(uint16_t *) (igmp_msg + IGMP_CHECKSUM_OFFSET) = 0;
checksum = in_cksum(igmp_msg, igmp_msg_len);
if (checksum != recv_checksum) {
zlog_warn("Recv IGMP report v3 from %s on %s: checksum mismatch: received=%x computed=%x",
from_str, ifp->name, recv_checksum, checksum);
return -1;
}
num_groups = ntohs(*(uint16_t *) (igmp_msg + IGMP_V3_REPORT_NUMGROUPS_OFFSET));
if (num_groups < 1) {
zlog_warn("Recv IGMP report v3 from %s on %s: missing group records",
from_str, ifp->name);
return -1;
}
if (PIM_DEBUG_IGMP_PACKETS) {
zlog_debug("Recv IGMP report v3 from %s on %s: size=%d checksum=%x groups=%d",
from_str, ifp->name, igmp_msg_len, checksum, num_groups);
}
group_record = (uint8_t *) igmp_msg + IGMP_V3_REPORT_GROUPPRECORD_OFFSET;
/* Scan groups */
for (i = 0; i < num_groups; ++i) {
struct in_addr rec_group;
uint8_t *sources;
uint8_t *src;
int rec_type;
int rec_auxdatalen;
int rec_num_sources;
int j;
struct prefix lncb;
struct prefix g;
if ((group_record + IGMP_V3_GROUP_RECORD_MIN_SIZE) > report_pastend) {
zlog_warn("Recv IGMP report v3 from %s on %s: group record beyond report end",
from_str, ifp->name);
return -1;
}
rec_type = group_record[IGMP_V3_GROUP_RECORD_TYPE_OFFSET];
rec_auxdatalen = group_record[IGMP_V3_GROUP_RECORD_AUXDATALEN_OFFSET];
rec_num_sources = ntohs(* (uint16_t *) (group_record + IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET));
memcpy(&rec_group, group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET, sizeof(struct in_addr));
if (PIM_DEBUG_IGMP_PACKETS) {
zlog_debug("Recv IGMP report v3 from %s on %s: record=%d type=%d auxdatalen=%d sources=%d group=%s",
from_str, ifp->name, i, rec_type, rec_auxdatalen, rec_num_sources, inet_ntoa(rec_group));
}
/* Scan sources */
sources = group_record + IGMP_V3_GROUP_RECORD_SOURCE_OFFSET;
for (j = 0, src = sources; j < rec_num_sources; ++j, src += 4) {
if ((src + 4) > report_pastend) {
zlog_warn("Recv IGMP report v3 from %s on %s: group source beyond report end",
from_str, ifp->name);
return -1;
}
if (PIM_DEBUG_IGMP_PACKETS) {
char src_str[200];
if (!inet_ntop(AF_INET, src, src_str , sizeof(src_str)))
sprintf(src_str, "<source?>");
zlog_debug("Recv IGMP report v3 from %s on %s: record=%d group=%s source=%s",
from_str, ifp->name, i, inet_ntoa(rec_group), src_str);
}
} /* for (sources) */
lncb.family = AF_INET;
lncb.u.prefix4.s_addr = 0x000000E0;
lncb.prefixlen = 24;
g.family = AF_INET;
g.u.prefix4 = rec_group;
g.prefixlen = 32;
/*
* If we receive a igmp report with the group in 224.0.0.0/24
* then we should ignore it
*/
if (prefix_match(&lncb, &g))
local_ncb = 1;
if (!local_ncb)
switch (rec_type) {
case IGMP_GRP_REC_TYPE_MODE_IS_INCLUDE:
igmpv3_report_isin(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
break;
case IGMP_GRP_REC_TYPE_MODE_IS_EXCLUDE:
igmpv3_report_isex(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources, 0);
break;
case IGMP_GRP_REC_TYPE_CHANGE_TO_INCLUDE_MODE:
igmpv3_report_toin(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
break;
case IGMP_GRP_REC_TYPE_CHANGE_TO_EXCLUDE_MODE:
igmpv3_report_toex(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
break;
case IGMP_GRP_REC_TYPE_ALLOW_NEW_SOURCES:
igmpv3_report_allow(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
break;
case IGMP_GRP_REC_TYPE_BLOCK_OLD_SOURCES:
igmpv3_report_block(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
break;
default:
zlog_warn("Recv IGMP report v3 from %s on %s: unknown record type: type=%d",
from_str, ifp->name, rec_type);
}
group_record += 8 + (rec_num_sources << 2) + (rec_auxdatalen << 2);
local_ncb = 0;
} /* for (group records) */
return 0;
} }

View File

@ -30,6 +30,13 @@
#define IGMP_V3_NUMSOURCES_OFFSET (10) #define IGMP_V3_NUMSOURCES_OFFSET (10)
#define IGMP_V3_SOURCES_OFFSET (12) #define IGMP_V3_SOURCES_OFFSET (12)
#define IGMP_GRP_REC_TYPE_MODE_IS_INCLUDE (1)
#define IGMP_GRP_REC_TYPE_MODE_IS_EXCLUDE (2)
#define IGMP_GRP_REC_TYPE_CHANGE_TO_INCLUDE_MODE (3)
#define IGMP_GRP_REC_TYPE_CHANGE_TO_EXCLUDE_MODE (4)
#define IGMP_GRP_REC_TYPE_ALLOW_NEW_SOURCES (5)
#define IGMP_GRP_REC_TYPE_BLOCK_OLD_SOURCES (6)
/* GMI: Group Membership Interval */ /* GMI: Group Membership Interval */
#define PIM_IGMP_GMI_MSEC(qrv,qqi,qri_dsec) ((qrv) * (1000 * (qqi)) + 100 * (qri_dsec)) #define PIM_IGMP_GMI_MSEC(qrv,qqi,qri_dsec) ((qrv) * (1000 * (qqi)) + 100 * (qri_dsec))
@ -54,15 +61,13 @@ void igmp_source_free(struct igmp_source *source);
void igmp_source_delete(struct igmp_source *source); void igmp_source_delete(struct igmp_source *source);
void igmp_source_delete_expired(struct list *source_list); void igmp_source_delete_expired(struct list *source_list);
int igmp_group_compat_mode(const struct igmp_sock *igmp,
const struct igmp_group *group);
void igmpv3_report_isin(struct igmp_sock *igmp, struct in_addr from, void igmpv3_report_isin(struct igmp_sock *igmp, struct in_addr from,
struct in_addr group_addr, struct in_addr group_addr,
int num_sources, struct in_addr *sources); int num_sources, struct in_addr *sources);
void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from, void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from,
struct in_addr group_addr, struct in_addr group_addr,
int num_sources, struct in_addr *sources); int num_sources, struct in_addr *sources,
int from_igmp_v2_report);
void igmpv3_report_toin(struct igmp_sock *igmp, struct in_addr from, void igmpv3_report_toin(struct igmp_sock *igmp, struct in_addr from,
struct in_addr group_addr, struct in_addr group_addr,
int num_sources, struct in_addr *sources); int num_sources, struct in_addr *sources);
@ -82,17 +87,24 @@ void igmp_source_timer_lower_to_lmqt(struct igmp_source *source);
struct igmp_source *igmp_find_source_by_addr(struct igmp_group *group, struct igmp_source *igmp_find_source_by_addr(struct igmp_group *group,
struct in_addr src_addr); struct in_addr src_addr);
void pim_igmp_send_membership_query(struct igmp_group *group, void igmp_v3_send_query (struct igmp_group *group,
int fd, int fd,
const char *ifname, const char *ifname,
char *query_buf, char *query_buf,
int query_buf_size, int query_buf_size,
int num_sources, int num_sources,
struct in_addr dst_addr, struct in_addr dst_addr,
struct in_addr group_addr, struct in_addr group_addr,
int query_max_response_time_dsec, int query_max_response_time_dsec,
uint8_t s_flag, uint8_t s_flag,
uint8_t querier_robustness_variable, uint8_t querier_robustness_variable,
uint16_t querier_query_interval); uint16_t querier_query_interval);
void igmp_v3_recv_query (struct igmp_sock *igmp, const char *from_str,
char *igmp_msg);
int igmp_v3_recv_report (struct igmp_sock *igmp,
struct in_addr from, const char *from_str,
char *igmp_msg, int igmp_msg_len);
#endif /* PIM_IGMPV3_H */ #endif /* PIM_IGMPV3_H */

View File

@ -23,6 +23,8 @@
#include "log.h" #include "log.h"
#include "prefix.h" #include "prefix.h"
#include "if.h" #include "if.h"
#include "vty.h"
#include "plist.h"
#include "pimd.h" #include "pimd.h"
#include "pim_str.h" #include "pim_str.h"
@ -30,15 +32,19 @@
#include "pim_msg.h" #include "pim_msg.h"
#include "pim_pim.h" #include "pim_pim.h"
#include "pim_join.h" #include "pim_join.h"
#include "pim_oil.h"
#include "pim_iface.h" #include "pim_iface.h"
#include "pim_hello.h" #include "pim_hello.h"
#include "pim_ifchannel.h" #include "pim_ifchannel.h"
#include "pim_rpf.h"
#include "pim_rp.h"
static void on_trace(const char *label, static void
struct interface *ifp, struct in_addr src) on_trace (const char *label,
struct interface *ifp, struct in_addr src)
{ {
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_TRACE) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
zlog_debug("%s: from %s on %s", zlog_debug("%s: from %s on %s",
label, src_str, ifp->name); label, src_str, ifp->name);
@ -49,58 +55,81 @@ static void recv_join(struct interface *ifp,
struct pim_neighbor *neigh, struct pim_neighbor *neigh,
uint16_t holdtime, uint16_t holdtime,
struct in_addr upstream, struct in_addr upstream,
struct in_addr group, struct prefix_sg *sg,
struct in_addr source,
uint8_t source_flags) uint8_t source_flags)
{ {
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_TRACE) {
char up_str[100]; char up_str[INET_ADDRSTRLEN];
char src_str[100]; char neigh_str[INET_ADDRSTRLEN];
char grp_str[100];
char neigh_str[100];
pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str)); pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
pim_inet4_dump("<src?>", source, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", group, grp_str, sizeof(grp_str));
pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str)); pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
zlog_warn("%s: join (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s", zlog_warn("%s: join (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str, pim_str_sg_dump (sg),
source_flags & PIM_RPT_BIT_MASK, source_flags & PIM_RPT_BIT_MASK,
source_flags & PIM_WILDCARD_BIT_MASK, source_flags & PIM_WILDCARD_BIT_MASK,
up_str, holdtime, neigh_str, ifp->name); up_str, holdtime, neigh_str, ifp->name);
} }
/*
* If the RPT and WC are set it's a (*,G)
* and the source is the RP
*/
if ((source_flags & PIM_RPT_BIT_MASK) &&
(source_flags & PIM_WILDCARD_BIT_MASK))
{
struct pim_rpf *rp = RP (sg->grp);
/*
* If the RP sent in the message is not
* our RP for the group, drop the message
*/
if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr)
return;
sg->src.s_addr = INADDR_ANY;
}
/* Restart join expiry timer */ /* Restart join expiry timer */
pim_ifchannel_join_add(ifp, neigh->source_addr, upstream, pim_ifchannel_join_add(ifp, neigh->source_addr, upstream,
source, group, source_flags, holdtime); sg, source_flags, holdtime);
} }
static void recv_prune(struct interface *ifp, static void recv_prune(struct interface *ifp,
struct pim_neighbor *neigh, struct pim_neighbor *neigh,
uint16_t holdtime, uint16_t holdtime,
struct in_addr upstream, struct in_addr upstream,
struct in_addr group, struct prefix_sg *sg,
struct in_addr source,
uint8_t source_flags) uint8_t source_flags)
{ {
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_TRACE) {
char up_str[100]; char up_str[INET_ADDRSTRLEN];
char src_str[100]; char neigh_str[INET_ADDRSTRLEN];
char grp_str[100];
char neigh_str[100];
pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str)); pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
pim_inet4_dump("<src?>", source, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", group, grp_str, sizeof(grp_str));
pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str)); pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
zlog_warn("%s: prune (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s", zlog_warn("%s: prune (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str, pim_str_sg_dump (sg),
source_flags & PIM_RPT_BIT_MASK, source_flags & PIM_RPT_BIT_MASK,
source_flags & PIM_WILDCARD_BIT_MASK, source_flags & PIM_WILDCARD_BIT_MASK,
up_str, holdtime, neigh_str, ifp->name); up_str, holdtime, neigh_str, ifp->name);
} }
pim_ifchannel_prune(ifp, upstream, source, group, source_flags, holdtime); if ((source_flags & PIM_RPT_BIT_MASK) &&
(source_flags & PIM_WILDCARD_BIT_MASK))
{
struct pim_rpf *rp = RP (sg->grp);
// Ignoring Prune *,G's at the moment.
if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr)
return;
sg->src.s_addr = INADDR_ANY;
}
pim_ifchannel_prune(ifp, upstream, sg, source_flags, holdtime);
} }
int pim_joinprune_recv(struct interface *ifp, int pim_joinprune_recv(struct interface *ifp,
@ -117,8 +146,6 @@ int pim_joinprune_recv(struct interface *ifp,
int remain; int remain;
int group; int group;
on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
buf = tlv_buf; buf = tlv_buf;
pastend = tlv_buf + tlv_buf_size; pastend = tlv_buf + tlv_buf_size;
@ -128,7 +155,7 @@ int pim_joinprune_recv(struct interface *ifp,
addr_offset = pim_parse_addr_ucast (&msg_upstream_addr, addr_offset = pim_parse_addr_ucast (&msg_upstream_addr,
buf, pastend - buf); buf, pastend - buf);
if (addr_offset < 1) { if (addr_offset < 1) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -141,8 +168,8 @@ int pim_joinprune_recv(struct interface *ifp,
Check upstream address family Check upstream address family
*/ */
if (msg_upstream_addr.family != AF_INET) { if (msg_upstream_addr.family != AF_INET) {
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_J_P) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s", zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -153,7 +180,7 @@ int pim_joinprune_recv(struct interface *ifp,
remain = pastend - buf; remain = pastend - buf;
if (remain < 4) { if (remain < 4) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s", zlog_warn("%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -168,28 +195,29 @@ int pim_joinprune_recv(struct interface *ifp,
++buf; ++buf;
++buf; ++buf;
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_J_P) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
char upstream_str[100]; char upstream_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4, pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
upstream_str, sizeof(upstream_str)); upstream_str, sizeof(upstream_str));
zlog_warn("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s", zlog_debug ("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
upstream_str, msg_num_groups, msg_holdtime, upstream_str, msg_num_groups, msg_holdtime,
src_str, ifp->name); src_str, ifp->name);
} }
/* Scan groups */ /* Scan groups */
for (group = 0; group < msg_num_groups; ++group) { for (group = 0; group < msg_num_groups; ++group) {
struct prefix msg_group_addr; struct prefix_sg sg;
struct prefix msg_source_addr;
uint8_t msg_source_flags; uint8_t msg_source_flags;
uint16_t msg_num_joined_sources; uint16_t msg_num_joined_sources;
uint16_t msg_num_pruned_sources; uint16_t msg_num_pruned_sources;
int source; int source;
struct pim_ifchannel *ch = NULL;
addr_offset = pim_parse_addr_group (&msg_group_addr, memset (&sg, 0, sizeof (struct prefix_sg));
addr_offset = pim_parse_addr_group (&sg,
buf, pastend - buf); buf, pastend - buf);
if (addr_offset < 1) { if (addr_offset < 1) {
return -5; return -5;
@ -198,7 +226,7 @@ int pim_joinprune_recv(struct interface *ifp,
remain = pastend - buf; remain = pastend - buf;
if (remain < 4) { if (remain < 4) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s", zlog_warn("%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -211,25 +239,25 @@ int pim_joinprune_recv(struct interface *ifp,
msg_num_pruned_sources = ntohs(*(const uint16_t *) buf); msg_num_pruned_sources = ntohs(*(const uint16_t *) buf);
buf += 2; buf += 2;
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_J_P) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
char upstream_str[100]; char upstream_str[INET_ADDRSTRLEN];
char group_str[100]; char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4, pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
upstream_str, sizeof(upstream_str)); upstream_str, sizeof(upstream_str));
pim_inet4_dump("<grp?>", msg_group_addr.u.prefix4, pim_inet4_dump("<grp?>", sg.grp,
group_str, sizeof(group_str)); group_str, sizeof(group_str));
zlog_warn("%s: join/prune upstream=%s group=%s/%d join_src=%d prune_src=%d from %s on %s", zlog_warn("%s: join/prune upstream=%s group=%s/32 join_src=%d prune_src=%d from %s on %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
upstream_str, group_str, msg_group_addr.prefixlen, upstream_str, group_str,
msg_num_joined_sources, msg_num_pruned_sources, msg_num_joined_sources, msg_num_pruned_sources,
src_str, ifp->name); src_str, ifp->name);
} }
/* Scan joined sources */ /* Scan joined sources */
for (source = 0; source < msg_num_joined_sources; ++source) { for (source = 0; source < msg_num_joined_sources; ++source) {
addr_offset = pim_parse_addr_source (&msg_source_addr, addr_offset = pim_parse_addr_source (&sg,
&msg_source_flags, &msg_source_flags,
buf, pastend - buf); buf, pastend - buf);
if (addr_offset < 1) { if (addr_offset < 1) {
@ -240,14 +268,20 @@ int pim_joinprune_recv(struct interface *ifp,
recv_join(ifp, neigh, msg_holdtime, recv_join(ifp, neigh, msg_holdtime,
msg_upstream_addr.u.prefix4, msg_upstream_addr.u.prefix4,
msg_group_addr.u.prefix4, &sg,
msg_source_addr.u.prefix4,
msg_source_flags); msg_source_flags);
if (sg.src.s_addr == INADDR_ANY)
{
ch = pim_ifchannel_find (ifp, &sg);
if (ch)
pim_ifchannel_set_star_g_join_state (ch, 0);
}
} }
/* Scan pruned sources */ /* Scan pruned sources */
for (source = 0; source < msg_num_pruned_sources; ++source) { for (source = 0; source < msg_num_pruned_sources; ++source) {
addr_offset = pim_parse_addr_source (&msg_source_addr, addr_offset = pim_parse_addr_source (&sg,
&msg_source_flags, &msg_source_flags,
buf, pastend - buf); buf, pastend - buf);
if (addr_offset < 1) { if (addr_offset < 1) {
@ -258,11 +292,12 @@ int pim_joinprune_recv(struct interface *ifp,
recv_prune(ifp, neigh, msg_holdtime, recv_prune(ifp, neigh, msg_holdtime,
msg_upstream_addr.u.prefix4, msg_upstream_addr.u.prefix4,
msg_group_addr.u.prefix4, &sg,
msg_source_addr.u.prefix4,
msg_source_flags); msg_source_flags);
} }
if (ch)
pim_ifchannel_set_star_g_join_state (ch, 1);
ch = NULL;
} /* scan groups */ } /* scan groups */
return 0; return 0;
@ -270,16 +305,14 @@ int pim_joinprune_recv(struct interface *ifp,
int pim_joinprune_send(struct interface *ifp, int pim_joinprune_send(struct interface *ifp,
struct in_addr upstream_addr, struct in_addr upstream_addr,
struct in_addr source_addr, struct pim_upstream *up,
struct in_addr group_addr,
int send_join) int send_join)
{ {
struct pim_interface *pim_ifp; struct pim_interface *pim_ifp;
uint8_t pim_msg[1000]; uint8_t pim_msg[9000];
const uint8_t *pastend = pim_msg + sizeof(pim_msg);
uint8_t *pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* room for pim header */
int pim_msg_size; int pim_msg_size;
int remain;
on_trace (__PRETTY_FUNCTION__, ifp, upstream_addr);
zassert(ifp); zassert(ifp);
@ -292,31 +325,23 @@ int pim_joinprune_send(struct interface *ifp,
return -1; return -1;
} }
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_J_P) {
char source_str[100]; char dst_str[INET_ADDRSTRLEN];
char group_str[100];
char dst_str[100];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str)); pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
zlog_debug("%s: sending %s(S,G)=(%s,%s) to upstream=%s on interface %s", zlog_debug("%s: sending %s(S,G)=%s to upstream=%s on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
send_join ? "Join" : "Prune", send_join ? "Join" : "Prune",
source_str, group_str, dst_str, ifp->name); up->sg_str, dst_str, ifp->name);
} }
if (PIM_INADDR_IS_ANY(upstream_addr)) { if (PIM_INADDR_IS_ANY(upstream_addr)) {
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_J_P) {
char source_str[100]; char dst_str[INET_ADDRSTRLEN];
char group_str[100];
char dst_str[100];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str)); pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
zlog_debug("%s: %s(S,G)=(%s,%s): upstream=%s is myself on interface %s", zlog_debug("%s: %s(S,G)=%s: upstream=%s is myself on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
send_join ? "Join" : "Prune", send_join ? "Join" : "Prune",
source_str, group_str, dst_str, ifp->name); up->sg_str, dst_str, ifp->name);
} }
return 0; return 0;
} }
@ -335,83 +360,14 @@ int pim_joinprune_send(struct interface *ifp,
/* /*
Build PIM message Build PIM message
*/ */
pim_msg_size = pim_msg_join_prune_encode (pim_msg, 9000, send_join,
up, upstream_addr, PIM_JP_HOLDTIME);
remain = pastend - pim_msg_curr; if (pim_msg_size < 0)
pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr, return pim_msg_size;
remain,
upstream_addr);
if (!pim_msg_curr) {
char dst_str[100];
pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
zlog_warn("%s: failure encoding destination address %s: space left=%d",
__PRETTY_FUNCTION__, dst_str, remain);
return -3;
}
remain = pastend - pim_msg_curr;
if (remain < 4) {
zlog_warn("%s: group will not fit: space left=%d",
__PRETTY_FUNCTION__, remain);
return -4;
}
*pim_msg_curr = 0; /* reserved */
++pim_msg_curr;
*pim_msg_curr = 1; /* number of groups */
++pim_msg_curr;
*((uint16_t *) pim_msg_curr) = htons(PIM_JP_HOLDTIME);
++pim_msg_curr;
++pim_msg_curr;
remain = pastend - pim_msg_curr;
pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr,
remain,
group_addr);
if (!pim_msg_curr) {
char group_str[100];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
zlog_warn("%s: failure encoding group address %s: space left=%d",
__PRETTY_FUNCTION__, group_str, remain);
return -5;
}
remain = pastend - pim_msg_curr;
if (remain < 4) {
zlog_warn("%s: sources will not fit: space left=%d",
__PRETTY_FUNCTION__, remain);
return -6;
}
/* number of joined sources */
*((uint16_t *) pim_msg_curr) = htons(send_join ? 1 : 0);
++pim_msg_curr;
++pim_msg_curr;
/* number of pruned sources */
*((uint16_t *) pim_msg_curr) = htons(send_join ? 0 : 1);
++pim_msg_curr;
++pim_msg_curr;
remain = pastend - pim_msg_curr;
pim_msg_curr = pim_msg_addr_encode_ipv4_source(pim_msg_curr,
remain,
source_addr);
if (!pim_msg_curr) {
char source_str[100];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: failure encoding source address %s: space left=%d",
__PRETTY_FUNCTION__, source_str, remain);
return -7;
}
/* Add PIM header */
pim_msg_size = pim_msg_curr - pim_msg;
pim_msg_build_header(pim_msg, pim_msg_size,
PIM_MSG_TYPE_JOIN_PRUNE);
if (pim_msg_send(pim_ifp->pim_sock_fd, if (pim_msg_send(pim_ifp->pim_sock_fd,
pim_ifp->primary_address,
qpim_all_pim_routers_addr, qpim_all_pim_routers_addr,
pim_msg, pim_msg,
pim_msg_size, pim_msg_size,

View File

@ -34,8 +34,7 @@ int pim_joinprune_recv(struct interface *ifp,
int pim_joinprune_send(struct interface *ifp, int pim_joinprune_send(struct interface *ifp,
struct in_addr upstream_addr, struct in_addr upstream_addr,
struct in_addr source_addr, struct pim_upstream *up,
struct in_addr group_addr,
int send_join); int send_join);
#endif /* PIM_JOIN_H */ #endif /* PIM_JOIN_H */

View File

@ -21,22 +21,39 @@
#include <zebra.h> #include <zebra.h>
#include "log.h" #include "log.h"
#include "prefix.h"
#include "vty.h"
#include "plist.h"
#include "pim_macro.h"
#include "pimd.h" #include "pimd.h"
#include "pim_str.h" #include "pim_macro.h"
#include "pim_iface.h" #include "pim_iface.h"
#include "pim_ifchannel.h" #include "pim_ifchannel.h"
#include "pim_rp.h"
/* /*
DownstreamJPState(S,G,I) is the per-interface state machine for DownstreamJPState(S,G,I) is the per-interface state machine for
receiving (S,G) Join/Prune messages. receiving (S,G) Join/Prune messages.
DownstreamJPState(S,G,I) is either Join or Prune-Pending ? DownstreamJPState(S,G,I) is either Join or Prune-Pending
DownstreamJPState(*,G,I) is either Join or Prune-Pending
*/ */
static int downstream_jpstate_isjoined(const struct pim_ifchannel *ch) static int downstream_jpstate_isjoined(const struct pim_ifchannel *ch)
{ {
return ch->ifjoin_state != PIM_IFJOIN_NOINFO; switch (ch->ifjoin_state)
{
case PIM_IFJOIN_NOINFO:
case PIM_IFJOIN_PRUNE:
case PIM_IFJOIN_PRUNE_TMP:
case PIM_IFJOIN_PRUNE_PENDING_TMP:
return 0;
break;
case PIM_IFJOIN_JOIN:
case PIM_IFJOIN_PRUNE_PENDING:
return 1;
break;
}
return 0;
} }
/* /*
@ -100,13 +117,9 @@ int pim_macro_ch_lost_assert(const struct pim_ifchannel *ch)
ifp = ch->interface; ifp = ch->interface;
if (!ifp) { if (!ifp) {
char src_str[100]; zlog_warn("%s: (S,G)=%s: null interface",
char grp_str[100];
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
zlog_warn("%s: (S,G)=(%s,%s): null interface",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str); ch->sg_str);
return 0; /* false */ return 0; /* false */
} }
@ -116,13 +129,9 @@ int pim_macro_ch_lost_assert(const struct pim_ifchannel *ch)
pim_ifp = ifp->info; pim_ifp = ifp->info;
if (!pim_ifp) { if (!pim_ifp) {
char src_str[100]; zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
char grp_str[100];
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str, ifp->name); ch->sg_str, ifp->name);
return 0; /* false */ return 0; /* false */
} }
@ -157,13 +166,9 @@ int pim_macro_chisin_pim_include(const struct pim_ifchannel *ch)
struct pim_interface *pim_ifp = ch->interface->info; struct pim_interface *pim_ifp = ch->interface->info;
if (!pim_ifp) { if (!pim_ifp) {
char src_str[100]; zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
char grp_str[100];
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str, ch->interface->name); ch->sg_str, ch->interface->name);
return 0; /* false */ return 0; /* false */
} }
@ -225,13 +230,8 @@ int pim_macro_ch_could_assert_eval(const struct pim_ifchannel *ch)
ifp = ch->interface; ifp = ch->interface;
if (!ifp) { if (!ifp) {
char src_str[100]; zlog_warn("%s: (S,G)=%s: null interface",
char grp_str[100]; __PRETTY_FUNCTION__, ch->sg_str);
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
zlog_warn("%s: (S,G)=(%s,%s): null interface",
__PRETTY_FUNCTION__,
src_str, grp_str);
return 0; /* false */ return 0; /* false */
} }
@ -350,7 +350,7 @@ static int pim_macro_chisin_inherited_olist(const struct pim_ifchannel *ch)
*/ */
int pim_macro_chisin_oiflist(const struct pim_ifchannel *ch) int pim_macro_chisin_oiflist(const struct pim_ifchannel *ch)
{ {
if (ch->upstream->join_state != PIM_UPSTREAM_JOINED) { if (ch->upstream->join_state == PIM_UPSTREAM_NOTJOINED) {
/* oiflist is NULL */ /* oiflist is NULL */
return 0; /* false */ return 0; /* false */
} }
@ -386,25 +386,15 @@ int pim_macro_assert_tracking_desired_eval(const struct pim_ifchannel *ch)
ifp = ch->interface; ifp = ch->interface;
if (!ifp) { if (!ifp) {
char src_str[100]; zlog_warn("%s: (S,G)=%s: null interface",
char grp_str[100]; __PRETTY_FUNCTION__, ch->sg_str);
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
zlog_warn("%s: (S,G)=(%s,%s): null interface",
__PRETTY_FUNCTION__,
src_str, grp_str);
return 0; /* false */ return 0; /* false */
} }
pim_ifp = ifp->info; pim_ifp = ifp->info;
if (!pim_ifp) { if (!pim_ifp) {
char src_str[100]; zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
char grp_str[100]; __PRETTY_FUNCTION__, ch->sg_str, ch->interface->name);
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s",
__PRETTY_FUNCTION__,
src_str, grp_str, ch->interface->name);
return 0; /* false */ return 0; /* false */
} }

View File

@ -43,10 +43,9 @@
#include "pim_version.h" #include "pim_version.h"
#include "pim_signals.h" #include "pim_signals.h"
#include "pim_zebra.h" #include "pim_zebra.h"
#include "pim_msdp.h"
#ifdef PIM_ZCLIENT_DEBUG #include "pim_iface.h"
extern int zclient_debug; #include "pim_rp.h"
#endif
extern struct host host; extern struct host host;
@ -70,6 +69,7 @@ zebra_capabilities_t _caps_p [] =
ZCAP_NET_ADMIN, ZCAP_NET_ADMIN,
ZCAP_SYS_ADMIN, ZCAP_SYS_ADMIN,
ZCAP_NET_RAW, ZCAP_NET_RAW,
ZCAP_BIND,
}; };
/* pimd privileges to run with */ /* pimd privileges to run with */
@ -104,18 +104,9 @@ Daemon which manages PIM.\n\n\
-A, --vty_addr Set vty's bind address\n\ -A, --vty_addr Set vty's bind address\n\
-P, --vty_port Set vty's port number\n\ -P, --vty_port Set vty's port number\n\
-v, --version Print program version\n\ -v, --version Print program version\n\
"
#ifdef PIM_ZCLIENT_DEBUG
"\
-Z, --debug_zclient Enable zclient debugging\n\
"
#endif
"\
-h, --help Display this help and exit\n\ -h, --help Display this help and exit\n\
\n\ \n\
Report bugs to %s\n", progname, PIMD_BUG_ADDRESS); Report bugs to %s\n", progname, PACKAGE_BUGREPORT);
} }
exit (status); exit (status);
@ -177,11 +168,6 @@ int main(int argc, char** argv, char** envp) {
print_version(progname); print_version(progname);
exit (0); exit (0);
break; break;
#ifdef PIM_ZCLIENT_DEBUG
case 'Z':
zclient_debug = 1;
break;
#endif
case 'h': case 'h':
usage (0); usage (0);
break; break;
@ -206,8 +192,12 @@ int main(int argc, char** argv, char** envp) {
vrf_init (); vrf_init ();
access_list_init(); access_list_init();
prefix_list_init (); prefix_list_init ();
prefix_list_add_hook (pim_rp_prefix_list_update);
prefix_list_delete_hook (pim_rp_prefix_list_update);
pim_route_map_init (); pim_route_map_init ();
pim_init(); pim_init();
pim_msdp_init (master);
/* /*
* Initialize zclient "update" and "lookup" sockets * Initialize zclient "update" and "lookup" sockets
@ -254,11 +244,6 @@ int main(int argc, char** argv, char** envp) {
PIM_DO_DEBUG_ZEBRA; PIM_DO_DEBUG_ZEBRA;
#endif #endif
#ifdef PIM_ZCLIENT_DEBUG
zlog_notice("PIM_ZCLIENT_DEBUG: zclient debugging is supported, mode is %s (see option -Z)",
zclient_debug ? "ON" : "OFF");
#endif
#ifdef PIM_CHECK_RECV_IFINDEX_SANITY #ifdef PIM_CHECK_RECV_IFINDEX_SANITY
zlog_notice("PIM_CHECK_RECV_IFINDEX_SANITY: will match sock/recv ifindex"); zlog_notice("PIM_CHECK_RECV_IFINDEX_SANITY: will match sock/recv ifindex");
#ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH #ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH

View File

@ -39,3 +39,11 @@ DEFINE_MTYPE(PIMD, PIM_UPSTREAM, "PIM upstream (S,G) state")
DEFINE_MTYPE(PIMD, PIM_SSMPINGD, "PIM sspimgd socket") DEFINE_MTYPE(PIMD, PIM_SSMPINGD, "PIM sspimgd socket")
DEFINE_MTYPE(PIMD, PIM_STATIC_ROUTE, "PIM Static Route") DEFINE_MTYPE(PIMD, PIM_STATIC_ROUTE, "PIM Static Route")
DEFINE_MTYPE(PIMD, PIM_BR, "PIM Bridge Router info") DEFINE_MTYPE(PIMD, PIM_BR, "PIM Bridge Router info")
DEFINE_MTYPE(PIMD, PIM_RP, "PIM RP info")
DEFINE_MTYPE(PIMD, PIM_FILTER_NAME, "PIM RP filter info")
DEFINE_MTYPE(PIMD, PIM_MSDP_PEER, "PIM MSDP peer")
DEFINE_MTYPE(PIMD, PIM_MSDP_MG_NAME, "PIM MSDP mesh-group name")
DEFINE_MTYPE(PIMD, PIM_MSDP_SA, "PIM MSDP source-active cache")
DEFINE_MTYPE(PIMD, PIM_MSDP_MG, "PIM MSDP mesh group")
DEFINE_MTYPE(PIMD, PIM_MSDP_MG_MBR, "PIM MSDP mesh group mbr")
DEFINE_MTYPE(PIMD, PIM_SEC_ADDR, "PIM secondary address")

View File

@ -38,5 +38,13 @@ DECLARE_MTYPE(PIM_UPSTREAM)
DECLARE_MTYPE(PIM_SSMPINGD) DECLARE_MTYPE(PIM_SSMPINGD)
DECLARE_MTYPE(PIM_STATIC_ROUTE) DECLARE_MTYPE(PIM_STATIC_ROUTE)
DECLARE_MTYPE(PIM_BR) DECLARE_MTYPE(PIM_BR)
DECLARE_MTYPE(PIM_RP)
DECLARE_MTYPE(PIM_FILTER_NAME)
DECLARE_MTYPE(PIM_MSDP_PEER)
DECLARE_MTYPE(PIM_MSDP_MG_NAME)
DECLARE_MTYPE(PIM_MSDP_SA)
DECLARE_MTYPE(PIM_MSDP_MG)
DECLARE_MTYPE(PIM_MSDP_MG_MBR)
DECLARE_MTYPE(PIM_SEC_ADDR)
#endif /* _QUAGGA_PIM_MEMORY_H */ #endif /* _QUAGGA_PIM_MEMORY_H */

View File

@ -23,8 +23,11 @@
#include "privs.h" #include "privs.h"
#include "if.h" #include "if.h"
#include "prefix.h" #include "prefix.h"
#include "vty.h"
#include "plist.h"
#include "pimd.h" #include "pimd.h"
#include "pim_rpf.h"
#include "pim_mroute.h" #include "pim_mroute.h"
#include "pim_oil.h" #include "pim_oil.h"
#include "pim_str.h" #include "pim_str.h"
@ -34,10 +37,14 @@
#include "pim_rp.h" #include "pim_rp.h"
#include "pim_oil.h" #include "pim_oil.h"
#include "pim_register.h" #include "pim_register.h"
#include "pim_ifchannel.h"
#include "pim_zlookup.h"
/* GLOBAL VARS */ /* GLOBAL VARS */
extern struct zebra_privs_t pimd_privs; extern struct zebra_privs_t pimd_privs;
static struct thread *qpim_mroute_socket_reader = NULL;
static void mroute_read_on(void); static void mroute_read_on(void);
static int pim_mroute_set(int fd, int enable) static int pim_mroute_set(int fd, int enable)
@ -45,62 +52,75 @@ static int pim_mroute_set(int fd, int enable)
int err; int err;
int opt = enable ? MRT_INIT : MRT_DONE; int opt = enable ? MRT_INIT : MRT_DONE;
socklen_t opt_len = sizeof(opt); socklen_t opt_len = sizeof(opt);
int rcvbuf = 1024 * 1024 * 8;
long flags;
err = setsockopt(fd, IPPROTO_IP, opt, &opt, opt_len); err = setsockopt(fd, IPPROTO_IP, opt, &opt, opt_len);
if (err) { if (err) {
int e = errno;
zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s", zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
__FILE__, __PRETTY_FUNCTION__, __FILE__, __PRETTY_FUNCTION__,
fd, enable ? "MRT_INIT" : "MRT_DONE", opt, e, safe_strerror(e)); fd, enable ? "MRT_INIT" : "MRT_DONE", opt, errno, safe_strerror(errno));
errno = e;
return -1; return -1;
} }
#if 0 err = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
zlog_info("%s %s: setsockopt(fd=%d,IPPROTO_IP,MRT_INIT,opt=%d): ok", if (err) {
__FILE__, __PRETTY_FUNCTION__, zlog_warn("%s: failure: setsockopt(fd=%d, SOL_SOCKET, %d): errno=%d: %s",
fd, opt); __PRETTY_FUNCTION__, fd, rcvbuf, errno, safe_strerror(errno));
#endif }
return 0; flags = fcntl(fd, F_GETFL, 0);
} if (flags < 0)
static int
pim_mroute_connected_to_source (struct interface *ifp, struct in_addr src)
{
struct listnode *cnode;
struct connected *c;
struct prefix p;
p.family = AF_INET;
p.u.prefix4 = src;
p.prefixlen = IPV4_MAX_BITLEN;
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
{ {
if ((c->address->family == AF_INET) && zlog_warn("Could not get flags on socket fd:%d %d %s",
prefix_match (CONNECTED_PREFIX (c), &p)) fd, errno, safe_strerror(errno));
{ close (fd);
return 1; return -1;
} }
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
{
zlog_warn("Could not set O_NONBLOCK on socket fd:%d %d %s",
fd, errno, safe_strerror(errno));
close(fd);
return -1;
} }
if (enable)
{
#if defined linux
int upcalls = IGMPMSG_WRVIFWHOLE;
opt = MRT_PIM;
err = setsockopt (fd, IPPROTO_IP, opt, &upcalls, sizeof (upcalls));
if (err)
{
zlog_warn ("Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
errno, safe_strerror (errno));
return -1;
}
#else
zlog_warn ("PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall");
#endif
}
return 0; return 0;
} }
static const char *igmpmsgtype2str[IGMPMSG_WHOLEPKT + 1] = { static const char *igmpmsgtype2str[IGMPMSG_WRVIFWHOLE + 1] = {
"<unknown_upcall?>", "<unknown_upcall?>",
"NOCACHE", "NOCACHE",
"WRONGVIF", "WRONGVIF",
"WHOLEPKT", }; "WHOLEPKT",
"WRVIFWHOLE" };
static int static int
pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg, pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg)
const char *src_str, const char *grp_str)
{ {
struct pim_interface *pim_ifp = ifp->info; struct pim_interface *pim_ifp = ifp->info;
struct pim_upstream *up; struct pim_upstream *up;
struct pim_rpf *rpg; struct pim_rpf *rpg;
struct prefix_sg sg;
struct channel_oil *oil;
rpg = RP(msg->im_dst); rpg = RP(msg->im_dst);
/* /*
@ -108,108 +128,131 @@ pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg
* the Interface type is SSM we don't need to * the Interface type is SSM we don't need to
* do anything here * do anything here
*/ */
if ((rpg->rpf_addr.s_addr == INADDR_NONE) || if ((pim_rpf_addr_is_inaddr_none (rpg)) ||
(!pim_ifp) || (!pim_ifp) ||
(!(PIM_I_am_DR(pim_ifp))) || (!(PIM_I_am_DR(pim_ifp))) ||
(pim_ifp->itype == PIM_INTERFACE_SSM)) (pim_ifp->itype == PIM_INTERFACE_SSM))
return 0; {
if (PIM_DEBUG_MROUTE_DETAIL)
zlog_debug ("%s: Interface is not configured correctly to handle incoming packet: Could be !DR, !pim_ifp, !SM, !RP",
__PRETTY_FUNCTION__);
return 0;
}
/* /*
* If we've received a multicast packet that isn't connected to * If we've received a multicast packet that isn't connected to
* us * us
*/ */
if (!pim_mroute_connected_to_source (ifp, msg->im_src)) if (!pim_if_connected_to_source (ifp, msg->im_src))
{ {
if (PIM_DEBUG_PIM_TRACE) if (PIM_DEBUG_MROUTE_DETAIL)
zlog_debug ("%s: Received incoming packet that does originate on our seg", zlog_debug ("%s: Received incoming packet that doesn't originate on our seg",
__PRETTY_FUNCTION__); __PRETTY_FUNCTION__);
return 0; return 0;
} }
if (PIM_DEBUG_PIM_TRACE) { memset (&sg, 0, sizeof (struct prefix_sg));
zlog_debug("%s: Adding a Route for %s from %s for WHOLEPKT consumption", sg.src = msg->im_src;
__PRETTY_FUNCTION__, grp_str, src_str); sg.grp = msg->im_dst;
oil = pim_channel_oil_add (&sg, pim_ifp->mroute_vif_index);
if (!oil) {
if (PIM_DEBUG_MROUTE) {
zlog_debug("%s: Failure to add channel oil for %s",
__PRETTY_FUNCTION__,
pim_str_sg_dump (&sg));
}
return 0;
} }
up = pim_upstream_add(msg->im_src, msg->im_dst, ifp); up = pim_upstream_add (&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR, __PRETTY_FUNCTION__);
if (!up) { if (!up) {
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_MROUTE) {
zlog_debug("%s: Failure to add upstream information for (%s,%s)", zlog_debug("%s: Failure to add upstream information for %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str); pim_str_sg_dump (&sg));
} }
return 0; return 0;
} }
pim_upstream_keep_alive_timer_start (up, PIM_KEEPALIVE_PERIOD); /*
* I moved this debug till after the actual add because
up->channel_oil = pim_channel_oil_add(msg->im_dst, * I want to take advantage of the up->sg_str being filled in.
msg->im_src, */
pim_ifp->mroute_vif_index); if (PIM_DEBUG_MROUTE) {
if (!up->channel_oil) { zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
if (PIM_DEBUG_PIM_TRACE) { __PRETTY_FUNCTION__, up->sg_str);
zlog_debug("%s: Failure to add channel oil for (%s,%s)",
__PRETTY_FUNCTION__,
src_str, grp_str);
}
return 0;
} }
PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
up->channel_oil = oil;
up->channel_oil->cc.pktcnt++; up->channel_oil->cc.pktcnt++;
PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
pim_channel_add_oif(up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_SOURCE); pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
up->join_state = PIM_UPSTREAM_JOINED;
return 0; return 0;
} }
static int static int
pim_mroute_msg_wholepkt (int fd, struct interface *ifp, const char *buf, pim_mroute_msg_wholepkt (int fd, struct interface *ifp, const char *buf)
const char *src_str, const char *grp_str)
{ {
struct pim_interface *pim_ifp; struct pim_interface *pim_ifp;
struct in_addr group; struct prefix_sg sg;
struct in_addr src;
struct pim_rpf *rpg; struct pim_rpf *rpg;
const struct ip *ip_hdr; const struct ip *ip_hdr;
struct pim_upstream *up; struct pim_upstream *up;
ip_hdr = (const struct ip *)buf; ip_hdr = (const struct ip *)buf;
src = ip_hdr->ip_src; memset (&sg, 0, sizeof (struct prefix_sg));
group = ip_hdr->ip_dst; sg.src = ip_hdr->ip_src;
sg.grp = ip_hdr->ip_dst;
up = pim_upstream_find(src, group); up = pim_upstream_find(&sg);
if (!up) { if (!up) {
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_MROUTE_DETAIL) {
zlog_debug("%s: Unable to find upstream channel WHOLEPKT(%s,%s)", zlog_debug("%s: Unable to find upstream channel WHOLEPKT%s",
__PRETTY_FUNCTION__, src_str, grp_str); __PRETTY_FUNCTION__, pim_str_sg_dump (&sg));
} }
return 0; return 0;
} }
pim_ifp = up->rpf.source_nexthop.interface->info; pim_ifp = up->rpf.source_nexthop.interface->info;
rpg = RP(group); rpg = RP(sg.grp);
if ((rpg->rpf_addr.s_addr == INADDR_NONE) || if ((pim_rpf_addr_is_inaddr_none (rpg)) ||
(!pim_ifp) || (!pim_ifp) ||
(!(PIM_I_am_DR(pim_ifp))) || (!(PIM_I_am_DR(pim_ifp))) ||
(pim_ifp->itype == PIM_INTERFACE_SSM)) { (pim_ifp->itype == PIM_INTERFACE_SSM)) {
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_MROUTE) {
zlog_debug("%s: Failed Check send packet", __PRETTY_FUNCTION__); zlog_debug("%s: Failed Check send packet", __PRETTY_FUNCTION__);
} }
return 0; return 0;
} }
pim_register_send((const struct ip *)(buf + sizeof(struct ip)), rpg); /*
* If we've received a register suppress
*/
if (!up->t_rs_timer)
pim_register_send((uint8_t *)buf + sizeof(struct ip), ntohs (ip_hdr->ip_len),
pim_ifp->primary_address, rpg, 0, up);
return 0; return 0;
} }
static int static int
pim_mroute_msg_wrongvif (int fd, struct interface *ifp, const struct igmpmsg *msg, pim_mroute_msg_wrongvif (int fd, struct interface *ifp, const struct igmpmsg *msg)
const char *src_str, const char *grp_str)
{ {
struct pim_ifchannel *ch; struct pim_ifchannel *ch;
struct pim_interface *pim_ifp; struct pim_interface *pim_ifp;
struct prefix_sg sg;
memset (&sg, 0, sizeof (struct prefix_sg));
sg.src = msg->im_src;
sg.grp = msg->im_dst;
/* /*
Send Assert(S,G) on iif as response to WRONGVIF kernel upcall. Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
@ -223,32 +266,39 @@ pim_mroute_msg_wrongvif (int fd, struct interface *ifp, const struct igmpmsg *ms
*/ */
if (!ifp) { if (!ifp) {
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_MROUTE)
zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) could not find input interface for input_vif_index=%d", zlog_debug("%s: WRONGVIF (S,G)=%s could not find input interface for input_vif_index=%d",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str, msg->im_vif); pim_str_sg_dump (&sg), msg->im_vif);
}
return -1; return -1;
} }
pim_ifp = ifp->info; pim_ifp = ifp->info;
if (!pim_ifp) { if (!pim_ifp) {
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_MROUTE)
zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) multicast not enabled on interface %s", zlog_debug("%s: WRONGVIF (S,G)=%s multicast not enabled on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str, ifp->name); pim_str_sg_dump (&sg), ifp->name);
}
return -2; return -2;
} }
ch = pim_ifchannel_find(ifp, msg->im_src, msg->im_dst); ch = pim_ifchannel_find(ifp, &sg);
if (!ch) { if (!ch) {
if (PIM_DEBUG_PIM_TRACE) { struct prefix_sg star_g = sg;
zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) could not find channel on interface %s", if (PIM_DEBUG_MROUTE)
zlog_debug("%s: WRONGVIF (S,G)=%s could not find channel on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str, ifp->name); pim_str_sg_dump(&sg), ifp->name);
star_g.src.s_addr = INADDR_ANY;
ch = pim_ifchannel_find(ifp, &star_g);
if (!ch) {
if (PIM_DEBUG_MROUTE)
zlog_debug("%s: WRONGVIF (*,G)=%s could not find channel on interface %s",
__PRETTY_FUNCTION__,
pim_str_sg_dump(&star_g), ifp->name);
return -3;
} }
return -3;
} }
/* /*
@ -266,28 +316,28 @@ pim_mroute_msg_wrongvif (int fd, struct interface *ifp, const struct igmpmsg *ms
*/ */
if (ch->ifassert_state != PIM_IFASSERT_NOINFO) { if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_MROUTE) {
zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) channel is not on Assert NoInfo state for interface %s", zlog_debug("%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str, ifp->name); ch->sg_str, ifp->name);
} }
return -4; return -4;
} }
if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) { if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_MROUTE) {
zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) interface %s is not downstream for channel", zlog_debug("%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str, ifp->name); ch->sg_str, ifp->name);
} }
return -5; return -5;
} }
if (assert_action_a1(ch)) { if (assert_action_a1(ch)) {
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_MROUTE) {
zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) assert_action_a1 failure on interface %s", zlog_debug("%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str, ifp->name); ch->sg_str, ifp->name);
} }
return -6; return -6;
} }
@ -295,107 +345,250 @@ pim_mroute_msg_wrongvif (int fd, struct interface *ifp, const struct igmpmsg *ms
return 0; return 0;
} }
static int
pim_mroute_msg_wrvifwhole (int fd, struct interface *ifp, const char *buf)
{
const struct ip *ip_hdr = (const struct ip *)buf;
struct pim_interface *pim_ifp;
struct pim_ifchannel *ch;
struct pim_upstream *up;
//struct prefix_sg star_g;
struct prefix_sg sg;
struct channel_oil *oil;
memset (&sg, 0, sizeof (struct prefix_sg));
sg.src = ip_hdr->ip_src;
sg.grp = ip_hdr->ip_dst;
ch = pim_ifchannel_find(ifp, &sg);
if (ch)
{
if (PIM_DEBUG_MROUTE)
zlog_debug ("WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
ch->sg_str, ifp->name);
return -1;
}
#if 0
star_g = sg;
star_g.src.s_addr = INADDR_ANY;
ch = pim_ifchannel_find(ifp, &star_g);
if (ch)
{
if (PIM_DEBUG_MROUTE)
zlog_debug ("WRVIFWHOLE (*,G)=%s found ifchannel on interface %s",
pim_str_sg_dump (&star_g), ifp->name);
return -1;
}
#endif
up = pim_upstream_find (&sg);
if (up)
{
struct pim_nexthop source;
struct pim_rpf *rpf = RP (sg.grp);
if (!rpf || !rpf->source_nexthop.interface)
return 0;
pim_ifp = rpf->source_nexthop.interface->info;
memset (&source, 0, sizeof (source));
/*
* If we are the fhr that means we are getting a callback during
* the pimreg period, so I believe we can ignore this packet
*/
if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
{
//No if channel, but upstream we are at the RP.
if (pim_nexthop_lookup (&source, up->upstream_register, 0) == 0)
pim_register_stop_send(source.interface, &sg, pim_ifp->primary_address, up->upstream_register);
if (!up->channel_oil)
up->channel_oil = pim_channel_oil_add (&sg, pim_ifp->mroute_vif_index);
pim_upstream_inherited_olist (up);
if (!up->channel_oil->installed)
pim_mroute_add (up->channel_oil, __PRETTY_FUNCTION__);
pim_upstream_set_sptbit (up, ifp);
}
else
{
if (I_am_RP (up->sg.grp))
{
if (pim_nexthop_lookup (&source, up->upstream_register, 0) == 0)
pim_register_stop_send(source.interface, &sg, pim_ifp->primary_address, up->upstream_register);
up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
}
pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
pim_upstream_inherited_olist (up);
pim_mroute_msg_wholepkt (fd, ifp, buf);
}
return 0;
}
pim_ifp = ifp->info;
oil = pim_channel_oil_add (&sg, pim_ifp->mroute_vif_index);
if (!oil->installed)
pim_mroute_add (oil, __PRETTY_FUNCTION__);
if (pim_if_connected_to_source (ifp, sg.src))
{
up = pim_upstream_add (&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR, __PRETTY_FUNCTION__);
if (!up)
{
if (PIM_DEBUG_MROUTE)
zlog_debug ("%s: WRONGVIF%s unable to create upstream on interface",
pim_str_sg_dump (&sg), ifp->name);
return -2;
}
PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
up->channel_oil = oil;
up->channel_oil->cc.pktcnt++;
pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
up->join_state = PIM_UPSTREAM_JOINED;
pim_upstream_inherited_olist (up);
// Send the packet to the RP
pim_mroute_msg_wholepkt (fd, ifp, buf);
}
return 0;
}
int pim_mroute_msg(int fd, const char *buf, int buf_size) int pim_mroute_msg(int fd, const char *buf, int buf_size)
{ {
struct interface *ifp; struct interface *ifp;
struct pim_interface *pim_ifp;
const struct ip *ip_hdr; const struct ip *ip_hdr;
const struct igmpmsg *msg; const struct igmpmsg *msg;
char src_str[100] = "<src?>"; char ip_src_str[INET_ADDRSTRLEN] = "";
char grp_str[100] = "<grp?>"; char ip_dst_str[INET_ADDRSTRLEN] = "";
char src_str[INET_ADDRSTRLEN] = "<src?>";
char grp_str[INET_ADDRSTRLEN] = "<grp?>";
struct in_addr ifaddr;
struct igmp_sock *igmp;
ip_hdr = (const struct ip *) buf; ip_hdr = (const struct ip *) buf;
/* kernel upcall must have protocol=0 */ if (ip_hdr->ip_p == IPPROTO_IGMP) {
if (ip_hdr->ip_p) {
/* this is not a kernel upcall */ /* We have the IP packet but we do not know which interface this packet was
if (PIM_DEBUG_PIM_TRACE) { * received on. Find the interface that is on the same subnet as the source
* of the IP packet.
*/
ifp = pim_if_lookup_address_vrf (ip_hdr->ip_src, VRF_DEFAULT);
if (!ifp) {
if (PIM_DEBUG_MROUTE_DETAIL) {
pim_inet4_dump("<src?>", ip_hdr->ip_src, ip_src_str, sizeof(ip_src_str));
pim_inet4_dump("<dst?>", ip_hdr->ip_dst, ip_dst_str, sizeof(ip_dst_str));
zlog_warn("%s: igmp kernel upcall could not find usable interface for %s -> %s",
__PRETTY_FUNCTION__,
ip_src_str,
ip_dst_str);
}
return 0;
}
pim_ifp = ifp->info;
ifaddr = pim_find_primary_addr(ifp);
igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, ifaddr);
if (PIM_DEBUG_MROUTE) {
pim_inet4_dump("<src?>", ip_hdr->ip_src, ip_src_str, sizeof(ip_src_str));
pim_inet4_dump("<dst?>", ip_hdr->ip_dst, ip_dst_str, sizeof(ip_dst_str));
zlog_warn("%s: igmp kernel upcall on %s(%p) for %s -> %s",
__PRETTY_FUNCTION__, ifp->name, igmp, ip_src_str, ip_dst_str);
}
if (igmp)
pim_igmp_packet(igmp, (char *)buf, buf_size);
} else if (ip_hdr->ip_p) {
if (PIM_DEBUG_MROUTE_DETAIL) {
pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", ip_hdr->ip_dst, grp_str, sizeof(grp_str)); pim_inet4_dump("<grp?>", ip_hdr->ip_dst, grp_str, sizeof(grp_str));
zlog_debug("%s: not a kernel upcall proto=%d src: %s dst: %s msg_size=%d", zlog_debug("%s: no kernel upcall proto=%d src: %s dst: %s msg_size=%d",
__PRETTY_FUNCTION__, ip_hdr->ip_p, src_str, grp_str, buf_size); __PRETTY_FUNCTION__, ip_hdr->ip_p, src_str, grp_str, buf_size);
} }
return 0;
}
msg = (const struct igmpmsg *) buf; } else {
msg = (const struct igmpmsg *) buf;
ifp = pim_if_find_by_vif_index(msg->im_vif); ifp = pim_if_find_by_vif_index(msg->im_vif);
if (PIM_DEBUG_PIM_TRACE) { if (!ifp)
pim_inet4_dump("<src?>", msg->im_src, src_str, sizeof(src_str)); return 0;
pim_inet4_dump("<grp?>", msg->im_dst, grp_str, sizeof(grp_str)); if (PIM_DEBUG_MROUTE) {
zlog_warn("%s: kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d", pim_inet4_dump("<src?>", msg->im_src, src_str, sizeof(src_str));
__PRETTY_FUNCTION__, pim_inet4_dump("<grp?>", msg->im_dst, grp_str, sizeof(grp_str));
igmpmsgtype2str[msg->im_msgtype], zlog_warn("%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d size=%d",
msg->im_msgtype, __PRETTY_FUNCTION__,
ip_hdr->ip_p, igmpmsgtype2str[msg->im_msgtype],
fd, msg->im_msgtype,
src_str, ip_hdr->ip_p,
grp_str, fd,
ifp ? ifp->name : "<ifname?>", src_str,
msg->im_vif); grp_str,
} ifp->name,
msg->im_vif, buf_size);
}
switch (msg->im_msgtype) { switch (msg->im_msgtype) {
case IGMPMSG_WRONGVIF: case IGMPMSG_WRONGVIF:
return pim_mroute_msg_wrongvif(fd, ifp, msg, src_str, grp_str); return pim_mroute_msg_wrongvif(fd, ifp, msg);
break; break;
case IGMPMSG_NOCACHE: case IGMPMSG_NOCACHE:
return pim_mroute_msg_nocache(fd, ifp, msg, src_str, grp_str); return pim_mroute_msg_nocache(fd, ifp, msg);
break; break;
case IGMPMSG_WHOLEPKT: case IGMPMSG_WHOLEPKT:
return pim_mroute_msg_wholepkt(fd, ifp, (const char *)msg, src_str, grp_str); return pim_mroute_msg_wholepkt(fd, ifp, (const char *)msg);
break; break;
default: case IGMPMSG_WRVIFWHOLE:
break; return pim_mroute_msg_wrvifwhole (fd, ifp, (const char *)msg);
break;
default:
break;
}
} }
return 0; return 0;
} }
static int mroute_read_msg(int fd)
{
const int msg_min_size = MAX(sizeof(struct ip), sizeof(struct igmpmsg));
char buf[1000];
int rd;
if (((int) sizeof(buf)) < msg_min_size) {
zlog_err("%s: fd=%d: buf size=%zu lower than msg_min=%d",
__PRETTY_FUNCTION__, fd, sizeof(buf), msg_min_size);
return -1;
}
rd = read(fd, buf, sizeof(buf));
if (rd < 0) {
zlog_warn("%s: failure reading fd=%d: errno=%d: %s",
__PRETTY_FUNCTION__, fd, errno, safe_strerror(errno));
return -2;
}
if (rd < msg_min_size) {
zlog_warn("%s: short message reading fd=%d: read=%d msg_min=%d",
__PRETTY_FUNCTION__, fd, rd, msg_min_size);
return -3;
}
return pim_mroute_msg(fd, buf, rd);
}
static int mroute_read(struct thread *t) static int mroute_read(struct thread *t)
{ {
static long long count;
char buf[10000];
int result = 0;
int cont = 1;
int fd; int fd;
int result; int rd;
zassert(t);
zassert(!THREAD_ARG(t));
fd = THREAD_FD(t); fd = THREAD_FD(t);
zassert(fd == qpim_mroute_socket_fd);
result = mroute_read_msg(fd); while (cont)
{
rd = read(fd, buf, sizeof(buf));
if (rd < 0) {
if (errno == EINTR)
continue;
if (errno == EWOULDBLOCK || errno == EAGAIN)
{
cont = 0;
break;
}
if (PIM_DEBUG_MROUTE)
zlog_warn("%s: failure reading fd=%d: errno=%d: %s",
__PRETTY_FUNCTION__, fd, errno, safe_strerror(errno));
goto done;
}
result = pim_mroute_msg(fd, buf, rd);
count++;
if (count % qpim_packet_process == 0)
cont = 0;
}
/* Keep reading */ /* Keep reading */
qpim_mroute_socket_reader = 0; done:
qpim_mroute_socket_reader = NULL;
mroute_read_on(); mroute_read_on();
return result; return result;
@ -450,8 +643,6 @@ int pim_mroute_socket_enable()
qpim_mroute_socket_creation = pim_time_monotonic_sec(); qpim_mroute_socket_creation = pim_time_monotonic_sec();
mroute_read_on(); mroute_read_on();
zassert(PIM_MROUTE_IS_ENABLED);
return 0; return 0;
} }
@ -475,8 +666,6 @@ int pim_mroute_socket_disable()
mroute_read_off(); mroute_read_off();
qpim_mroute_socket_fd = -1; qpim_mroute_socket_fd = -1;
zassert(PIM_MROUTE_IS_DISABLED);
return 0; return 0;
} }
@ -521,16 +710,14 @@ int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr, unsigned ch
err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_VIF, (void*) &vc, sizeof(vc)); err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_VIF, (void*) &vc, sizeof(vc));
if (err) { if (err) {
char ifaddr_str[100]; char ifaddr_str[INET_ADDRSTRLEN];
int e = errno;
pim_inet4_dump("<ifaddr?>", ifaddr, ifaddr_str, sizeof(ifaddr_str)); pim_inet4_dump("<ifaddr?>", ifaddr, ifaddr_str, sizeof(ifaddr_str));
zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s", zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s",
__FILE__, __PRETTY_FUNCTION__, __FILE__, __PRETTY_FUNCTION__,
qpim_mroute_socket_fd, ifp->ifindex, ifaddr_str, flags, qpim_mroute_socket_fd, ifp->ifindex, ifaddr_str, flags,
e, safe_strerror(e)); errno, safe_strerror(errno));
errno = e;
return -2; return -2;
} }
@ -553,22 +740,21 @@ int pim_mroute_del_vif(int vif_index)
err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_VIF, (void*) &vc, sizeof(vc)); err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_VIF, (void*) &vc, sizeof(vc));
if (err) { if (err) {
int e = errno;
zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s", zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
__FILE__, __PRETTY_FUNCTION__, __FILE__, __PRETTY_FUNCTION__,
qpim_mroute_socket_fd, vif_index, qpim_mroute_socket_fd, vif_index,
e, safe_strerror(e)); errno, safe_strerror(errno));
errno = e;
return -2; return -2;
} }
return 0; return 0;
} }
int pim_mroute_add(struct channel_oil *c_oil) int pim_mroute_add(struct channel_oil *c_oil, const char *name)
{ {
int err; int err;
int orig = 0; int orig = 0;
int orig_iif_vif = 0;
qpim_mroute_add_last = pim_time_monotonic_sec(); qpim_mroute_add_last = pim_time_monotonic_sec();
++qpim_mroute_add_events; ++qpim_mroute_add_events;
@ -589,27 +775,57 @@ int pim_mroute_add(struct channel_oil *c_oil)
c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = 1; c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = 1;
} }
/*
* If we have an unresolved cache entry for the S,G
* it is owned by the pimreg for the incoming IIF
* So set pimreg as the IIF temporarily to cause
* the packets to be forwarded. Then set it
* to the correct IIF afterwords.
*/
if (!c_oil->installed && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY &&
c_oil->oil.mfcc_parent != 0)
{
orig_iif_vif = c_oil->oil.mfcc_parent;
c_oil->oil.mfcc_parent = 0;
}
err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_MFC, err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_MFC,
&c_oil->oil, sizeof(c_oil->oil)); &c_oil->oil, sizeof(c_oil->oil));
if (!err && !c_oil->installed && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY &&
orig_iif_vif != 0)
{
c_oil->oil.mfcc_parent = orig_iif_vif;
err = setsockopt (qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_MFC,
&c_oil->oil, sizeof (c_oil->oil));
}
if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY) if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = orig; c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = orig;
if (err) { if (err) {
int e = errno;
zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s", zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
__FILE__, __PRETTY_FUNCTION__, __FILE__, __PRETTY_FUNCTION__,
qpim_mroute_socket_fd, qpim_mroute_socket_fd,
e, safe_strerror(e)); errno, safe_strerror(errno));
errno = e;
return -2; return -2;
} }
if (PIM_DEBUG_MROUTE)
{
struct prefix_sg sg;
sg.src = c_oil->oil.mfcc_origin;
sg.grp = c_oil->oil.mfcc_mcastgrp;
zlog_debug("%s(%s), Added Route: %s to mroute table",
__PRETTY_FUNCTION__, name, pim_str_sg_dump(&sg));
}
c_oil->installed = 1; c_oil->installed = 1;
return 0; return 0;
} }
int pim_mroute_del (struct channel_oil *c_oil) int pim_mroute_del (struct channel_oil *c_oil, const char *name)
{ {
int err; int err;
@ -624,15 +840,24 @@ int pim_mroute_del (struct channel_oil *c_oil)
err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_MFC, &c_oil->oil, sizeof(c_oil->oil)); err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_MFC, &c_oil->oil, sizeof(c_oil->oil));
if (err) { if (err) {
int e = errno; if (PIM_DEBUG_MROUTE)
zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s", zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
__FILE__, __PRETTY_FUNCTION__, __FILE__, __PRETTY_FUNCTION__,
qpim_mroute_socket_fd, qpim_mroute_socket_fd,
e, safe_strerror(e)); errno, safe_strerror(errno));
errno = e;
return -2; return -2;
} }
if (PIM_DEBUG_MROUTE)
{
struct prefix_sg sg;
sg.src = c_oil->oil.mfcc_origin;
sg.grp = c_oil->oil.mfcc_mcastgrp;
zlog_debug("%s(%s), Deleted Route: %s from mroute table",
__PRETTY_FUNCTION__, name, pim_str_sg_dump(&sg));
}
c_oil->installed = 0; c_oil->installed = 0;
return 0; return 0;
@ -643,28 +868,46 @@ pim_mroute_update_counters (struct channel_oil *c_oil)
{ {
struct sioc_sg_req sgreq; struct sioc_sg_req sgreq;
memset (&sgreq, 0, sizeof(sgreq));
sgreq.src = c_oil->oil.mfcc_origin;
sgreq.grp = c_oil->oil.mfcc_mcastgrp;
c_oil->cc.oldpktcnt = c_oil->cc.pktcnt; c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
c_oil->cc.oldbytecnt = c_oil->cc.bytecnt; c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
c_oil->cc.oldwrong_if = c_oil->cc.wrong_if; c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
if (!c_oil->installed)
{
c_oil->cc.lastused = 100 * qpim_keep_alive_time;
if (PIM_DEBUG_MROUTE)
{
struct prefix_sg sg;
sg.src = c_oil->oil.mfcc_origin;
sg.grp = c_oil->oil.mfcc_mcastgrp;
if (PIM_DEBUG_MROUTE)
zlog_debug("Channel(%s) is not installed no need to collect data from kernel",
pim_str_sg_dump (&sg));
}
return;
}
memset (&sgreq, 0, sizeof(sgreq));
sgreq.src = c_oil->oil.mfcc_origin;
sgreq.grp = c_oil->oil.mfcc_mcastgrp;
pim_zlookup_sg_statistics (c_oil);
if (ioctl (qpim_mroute_socket_fd, SIOCGETSGCNT, &sgreq)) if (ioctl (qpim_mroute_socket_fd, SIOCGETSGCNT, &sgreq))
{ {
char group_str[100]; if (PIM_DEBUG_MROUTE)
char source_str[100]; {
struct prefix_sg sg;
pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); sg.src = c_oil->oil.mfcc_origin;
pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); sg.grp = c_oil->oil.mfcc_mcastgrp;
zlog_warn ("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s,%s): errno=%d: %s", zlog_warn ("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s): errno=%d: %s",
(unsigned long)SIOCGETSGCNT, (unsigned long)SIOCGETSGCNT,
source_str, pim_str_sg_dump (&sg),
group_str, errno,
errno, safe_strerror(errno));
safe_strerror(errno)); }
return; return;
} }

View File

@ -157,6 +157,10 @@ struct igmpmsg
#endif #endif
#endif #endif
#ifndef IGMPMSG_WRVIFWHOLE
#define IGMPMSG_WRVIFWHOLE 4 /* For PIM processing */
#endif
/* /*
Above: from <linux/mroute.h> Above: from <linux/mroute.h>
*/ */
@ -167,8 +171,8 @@ int pim_mroute_socket_disable(void);
int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr, unsigned char flags); int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr, unsigned char flags);
int pim_mroute_del_vif(int vif_index); int pim_mroute_del_vif(int vif_index);
int pim_mroute_add(struct channel_oil *c_oil); int pim_mroute_add(struct channel_oil *c_oil, const char *name);
int pim_mroute_del(struct channel_oil *c_oil); int pim_mroute_del(struct channel_oil *c_oil, const char *name);
int pim_mroute_msg(int fd, const char *buf, int buf_size); int pim_mroute_msg(int fd, const char *buf, int buf_size);

1606
pimd/pim_msdp.c Normal file

File diff suppressed because it is too large Load Diff

233
pimd/pim_msdp.h Normal file
View File

@ -0,0 +1,233 @@
/*
* IP MSDP for Quagga
* Copyright (C) 2016 Cumulus Networks, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifndef PIM_MSDP_H
#define PIM_MSDP_H
enum pim_msdp_peer_state {
PIM_MSDP_DISABLED,
PIM_MSDP_INACTIVE,
PIM_MSDP_LISTEN,
PIM_MSDP_CONNECTING,
PIM_MSDP_ESTABLISHED
};
/* SA and KA TLVs are processed; rest ignored */
enum pim_msdp_tlv {
PIM_MSDP_V4_SOURCE_ACTIVE = 1,
PIM_MSDP_V4_SOURCE_ACTIVE_REQUEST,
PIM_MSDP_V4_SOURCE_ACTIVE_RESPONSE,
PIM_MSDP_KEEPALIVE,
PIM_MSDP_RESERVED,
PIM_MSDP_TRACEROUTE_PROGRESS,
PIM_MSDP_TRACEROUTE_REPLY,
};
/* MSDP error codes */
enum pim_msdp_err {
PIM_MSDP_ERR_NONE = 0,
PIM_MSDP_ERR_OOM = -1,
PIM_MSDP_ERR_PEER_EXISTS = -2,
PIM_MSDP_ERR_MAX_MESH_GROUPS = -3,
PIM_MSDP_ERR_NO_PEER = -4,
PIM_MSDP_ERR_MG_MBR_EXISTS = -5,
PIM_MSDP_ERR_NO_MG = -6,
PIM_MSDP_ERR_NO_MG_MBR = -7,
PIM_MSDP_ERR_SIP_EQ_DIP = -8,
};
#define PIM_MSDP_STATE_STRLEN 16
#define PIM_MSDP_UPTIME_STRLEN 80
#define PIM_MSDP_TIMER_STRLEN 12
#define PIM_MSDP_TCP_PORT 639
#define PIM_MSDP_SOCKET_SNDBUF_SIZE 65536
enum pim_msdp_sa_flags {
PIM_MSDP_SAF_NONE = 0,
/* There are two cases where we can pickup an active source locally -
* 1. We are RP and got a source-register from the FHR
* 2. We are RP and FHR and learnt a new directly connected source on a
* DR interface */
PIM_MSDP_SAF_LOCAL = (1 << 0),
/* We got this in the MSDP SA TLV from a peer (and this passed peer-RPF
* checks) */
PIM_MSDP_SAF_PEER = (1 << 1),
PIM_MSDP_SAF_REF = (PIM_MSDP_SAF_LOCAL | PIM_MSDP_SAF_PEER),
PIM_MSDP_SAF_STALE = (1 << 2), /* local entries can get kicked out on
* misc pim events such as RP change */
PIM_MSDP_SAF_UP_DEL_IN_PROG = (1 << 3)
};
struct pim_msdp_sa {
struct prefix_sg sg;
char sg_str[PIM_SG_LEN];
struct in_addr rp; /* Last RP address associated with this SA */
struct in_addr peer; /* last peer from who we heard this SA */
enum pim_msdp_sa_flags flags;
/* rfc-3618 is missing default value for SA-hold-down-Period. pulled
* this number from industry-standards */
#define PIM_MSDP_SA_HOLD_TIME ((3*60)+30)
struct thread *sa_state_timer; // 5.6
int64_t uptime;
struct pim_upstream *up;
};
enum pim_msdp_peer_flags {
PIM_MSDP_PEERF_NONE = 0,
PIM_MSDP_PEERF_LISTENER = (1 << 0),
#define PIM_MSDP_PEER_IS_LISTENER(mp) (mp->flags & PIM_MSDP_PEERF_LISTENER)
PIM_MSDP_PEERF_SA_JUST_SENT = (1 << 1)
};
struct pim_msdp_peer {
/* configuration */
struct in_addr local;
struct in_addr peer;
char *mesh_group_name;
char key_str[INET_ADDRSTRLEN];
/* state */
enum pim_msdp_peer_state state;
enum pim_msdp_peer_flags flags;
/* TCP socket info */
union sockunion su_local;
union sockunion su_peer;
int fd;
/* protocol timers */
#define PIM_MSDP_PEER_HOLD_TIME 75
struct thread *hold_timer; // 5.4
#define PIM_MSDP_PEER_KA_TIME 60
struct thread *ka_timer; // 5.5
#define PIM_MSDP_PEER_CONNECT_RETRY_TIME 30
struct thread *cr_timer; // 5.6
/* packet thread and buffers */
uint32_t packet_size;
struct stream *ibuf;
struct stream_fifo *obuf;
struct thread *t_read;
struct thread *t_write;
/* stats */
uint32_t conn_attempts;
uint32_t est_flaps;
uint32_t sa_cnt; /* number of SAs attributed to this peer */
#define PIM_MSDP_PEER_LAST_RESET_STR 20
char last_reset[PIM_MSDP_PEER_LAST_RESET_STR];
/* packet stats */
uint32_t ka_tx_cnt;
uint32_t sa_tx_cnt;
uint32_t ka_rx_cnt;
uint32_t sa_rx_cnt;
uint32_t unk_rx_cnt;
/* timestamps */
int64_t uptime;
};
struct pim_msdp_mg_mbr {
struct in_addr mbr_ip;
struct pim_msdp_peer *mp;
};
/* PIM MSDP mesh-group */
struct pim_msdp_mg {
char *mesh_group_name;
struct in_addr src_ip;
uint32_t mbr_cnt;
struct list *mbr_list;
};
enum pim_msdp_flags {
PIM_MSDPF_NONE = 0,
PIM_MSDPF_ENABLE = (1 << 0),
PIM_MSDPF_LISTENER = (1 << 1)
};
struct pim_msdp_listener {
int fd;
union sockunion su;
struct thread *thread;
};
struct pim_msdp {
enum pim_msdp_flags flags;
struct thread_master *master;
struct pim_msdp_listener listener;
uint32_t rejected_accepts;
/* MSDP peer info */
struct hash *peer_hash;
struct list *peer_list;
/* MSDP active-source info */
#define PIM_MSDP_SA_ADVERTISMENT_TIME 60
struct thread *sa_adv_timer; // 5.6
struct hash *sa_hash;
struct list *sa_list;
uint32_t local_cnt;
/* keep a scratch pad for building SA TLVs */
struct stream *work_obuf;
struct in_addr originator_id;
/* currently only one mesh-group is supported - so just stash it here */
struct pim_msdp_mg *mg;
};
#define PIM_MSDP_PEER_READ_ON(mp) THREAD_READ_ON(msdp->master, mp->t_read, pim_msdp_read, mp, mp->fd);
#define PIM_MSDP_PEER_WRITE_ON(mp) THREAD_WRITE_ON(msdp->master, mp->t_write, pim_msdp_write, mp, mp->fd);
#define PIM_MSDP_PEER_READ_OFF(mp) THREAD_READ_OFF(mp->t_read)
#define PIM_MSDP_PEER_WRITE_OFF(mp) THREAD_WRITE_OFF(mp->t_write)
extern struct pim_msdp *msdp;
void pim_msdp_init(struct thread_master *master);
void pim_msdp_exit(void);
enum pim_msdp_err pim_msdp_peer_add(struct in_addr peer, struct in_addr local, const char *mesh_group_name, struct pim_msdp_peer **mp_p);
enum pim_msdp_err pim_msdp_peer_del(struct in_addr peer_addr);
char *pim_msdp_state_dump(enum pim_msdp_peer_state state, char *buf, int buf_size);
struct pim_msdp_peer *pim_msdp_peer_find(struct in_addr peer_addr);
void pim_msdp_peer_established(struct pim_msdp_peer *mp);
void pim_msdp_peer_pkt_rxed(struct pim_msdp_peer *mp);
void pim_msdp_peer_stop_tcp_conn(struct pim_msdp_peer *mp, bool chg_state);
void pim_msdp_peer_reset_tcp_conn(struct pim_msdp_peer *mp, const char *rc_str);
int pim_msdp_write(struct thread *thread);
char *pim_msdp_peer_key_dump(struct pim_msdp_peer *mp, char *buf, int buf_size, bool long_format);
int pim_msdp_config_write(struct vty *vty);
void pim_msdp_peer_pkt_txed(struct pim_msdp_peer *mp);
void pim_msdp_sa_ref(struct pim_msdp_peer *mp, struct prefix_sg *sg, struct in_addr rp);
void pim_msdp_sa_local_update(struct pim_upstream *up);
void pim_msdp_sa_local_del(struct prefix_sg *sg);
void pim_msdp_i_am_rp_changed(void);
bool pim_msdp_peer_rpf_check(struct pim_msdp_peer *mp, struct in_addr rp);
void pim_msdp_up_join_state_changed(struct pim_upstream *xg_up);
void pim_msdp_up_del(struct prefix_sg *sg);
enum pim_msdp_err pim_msdp_mg_mbr_add(const char *mesh_group_name, struct in_addr mbr_ip);
enum pim_msdp_err pim_msdp_mg_mbr_del(const char *mesh_group_name, struct in_addr mbr_ip);
enum pim_msdp_err pim_msdp_mg_src_del(const char *mesh_group_name);
enum pim_msdp_err pim_msdp_mg_src_add(const char *mesh_group_name, struct in_addr src_ip);
enum pim_msdp_err pim_msdp_mg_del(const char *mesh_group_name);
#endif

696
pimd/pim_msdp_packet.c Normal file
View File

@ -0,0 +1,696 @@
/*
* IP MSDP packet helper
* Copyright (C) 2016 Cumulus Networks, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <zebra.h>
#include <lib/log.h>
#include <lib/network.h>
#include <lib/stream.h>
#include <lib/thread.h>
#include <lib/vty.h>
#include "pimd.h"
#include "pim_str.h"
#include "pim_msdp.h"
#include "pim_msdp_packet.h"
#include "pim_msdp_socket.h"
static char *
pim_msdp_pkt_type_dump(enum pim_msdp_tlv type, char *buf, int buf_size)
{
switch (type) {
case PIM_MSDP_V4_SOURCE_ACTIVE:
snprintf(buf, buf_size, "%s", "SA");
break;
case PIM_MSDP_V4_SOURCE_ACTIVE_REQUEST:
snprintf(buf, buf_size, "%s", "SA_REQ");
break;
case PIM_MSDP_V4_SOURCE_ACTIVE_RESPONSE:
snprintf(buf, buf_size, "%s", "SA_RESP");
break;
case PIM_MSDP_KEEPALIVE:
snprintf(buf, buf_size, "%s", "KA");
break;
case PIM_MSDP_RESERVED:
snprintf(buf, buf_size, "%s", "RSVD");
break;
case PIM_MSDP_TRACEROUTE_PROGRESS:
snprintf(buf, buf_size, "%s", "TRACE_PROG");
break;
case PIM_MSDP_TRACEROUTE_REPLY:
snprintf(buf, buf_size, "%s", "TRACE_REPLY");
break;
default:
snprintf(buf, buf_size, "UNK-%d", type);
}
return buf;
}
static void
pim_msdp_pkt_sa_dump_one(struct stream *s)
{
struct prefix_sg sg;
/* just throw away the three reserved bytes */
stream_get3(s);
/* throw away the prefix length also */
stream_getc(s);
memset(&sg, 0, sizeof (struct prefix_sg));
sg.grp.s_addr = stream_get_ipv4(s);
sg.src.s_addr = stream_get_ipv4(s);
zlog_debug(" sg %s", pim_str_sg_dump(&sg));
}
static void
pim_msdp_pkt_sa_dump(struct stream *s)
{
int entry_cnt;
int i;
struct in_addr rp; /* Last RP address associated with this SA */
entry_cnt = stream_getc(s);
rp.s_addr = stream_get_ipv4(s);
if (PIM_DEBUG_MSDP_PACKETS) {
char rp_str[INET_ADDRSTRLEN];
pim_inet4_dump("<rp?>", rp, rp_str, sizeof(rp_str));
zlog_debug(" entry_cnt %d rp %s", entry_cnt, rp_str);
}
/* dump SAs */
for (i = 0; i < entry_cnt; ++i) {
pim_msdp_pkt_sa_dump_one(s);
}
}
static void
pim_msdp_pkt_dump(struct pim_msdp_peer *mp, int type, int len, bool rx,
struct stream *s)
{
char type_str[PIM_MSDP_PKT_TYPE_STRLEN];
pim_msdp_pkt_type_dump(type, type_str, sizeof(type_str));
zlog_debug("MSDP peer %s pkt %s type %s len %d",
mp->key_str, rx?"rx":"tx", type_str, len);
if (!s) {
return;
}
switch(type) {
case PIM_MSDP_V4_SOURCE_ACTIVE:
pim_msdp_pkt_sa_dump(s);
break;
default:;
}
}
/* Check file descriptor whether connect is established. */
static void
pim_msdp_connect_check(struct pim_msdp_peer *mp)
{
int status;
socklen_t slen;
int ret;
if (mp->state != PIM_MSDP_CONNECTING) {
/* if we are here it means we are not in a connecting or established state
* for now treat this as a fatal error */
pim_msdp_peer_reset_tcp_conn(mp, "invalid-state");
return;
}
PIM_MSDP_PEER_READ_OFF(mp);
PIM_MSDP_PEER_WRITE_OFF(mp);
/* Check file descriptor. */
slen = sizeof(status);
ret = getsockopt(mp->fd, SOL_SOCKET, SO_ERROR, (void *)&status, &slen);
/* If getsockopt is fail, this is fatal error. */
if (ret < 0) {
zlog_err("can't get sockopt for nonblocking connect");
pim_msdp_peer_reset_tcp_conn(mp, "connect-failed");
return;
}
/* When status is 0 then TCP connection is established. */
if (PIM_DEBUG_MSDP_INTERNAL) {
zlog_debug("MSDP peer %s pim_connect_check %s", mp->key_str, status?"fail":"success");
}
if (status == 0) {
pim_msdp_peer_established(mp);
} else {
pim_msdp_peer_reset_tcp_conn(mp, "connect-failed");
}
}
static void
pim_msdp_pkt_delete(struct pim_msdp_peer *mp)
{
stream_free(stream_fifo_pop(mp->obuf));
}
static void
pim_msdp_pkt_add(struct pim_msdp_peer *mp, struct stream *s)
{
stream_fifo_push(mp->obuf, s);
}
static void
pim_msdp_write_proceed_actions(struct pim_msdp_peer *mp)
{
if (stream_fifo_head(mp->obuf)) {
PIM_MSDP_PEER_WRITE_ON(mp);
}
}
int
pim_msdp_write(struct thread *thread)
{
struct pim_msdp_peer *mp;
struct stream *s;
int num;
enum pim_msdp_tlv type;
int len;
int work_cnt = 0;
int work_max_cnt = 100;
mp = THREAD_ARG(thread);
mp->t_write = NULL;
if (PIM_DEBUG_MSDP_INTERNAL) {
zlog_debug("MSDP peer %s pim_msdp_write", mp->key_str);
}
if (mp->fd < 0) {
return -1;
}
/* check if TCP connection is established */
if (mp->state != PIM_MSDP_ESTABLISHED) {
pim_msdp_connect_check(mp);
return 0;
}
s = stream_fifo_head(mp->obuf);
if (!s) {
pim_msdp_write_proceed_actions(mp);
return 0;
}
sockopt_cork(mp->fd, 1);
/* Nonblocking write until TCP output buffer is full */
do
{
int writenum;
/* Number of bytes to be sent */
writenum = stream_get_endp(s) - stream_get_getp(s);
/* Call write() system call */
num = write(mp->fd, STREAM_PNT(s), writenum);
if (num < 0) {
/* write failed either retry needed or error */
if (ERRNO_IO_RETRY(errno)) {
if (PIM_DEBUG_MSDP_INTERNAL) {
zlog_debug("MSDP peer %s pim_msdp_write io retry", mp->key_str);
}
break;
}
pim_msdp_peer_reset_tcp_conn(mp, "pkt-tx-failed");
return 0;
}
if (num != writenum) {
/* Partial write */
stream_forward_getp(s, num);
if (PIM_DEBUG_MSDP_INTERNAL) {
zlog_debug("MSDP peer %s pim_msdp_partial_write", mp->key_str);
}
break;
}
/* Retrieve msdp packet type. */
stream_set_getp(s,0);
type = stream_getc(s);
len = stream_getw(s);
switch (type)
{
case PIM_MSDP_KEEPALIVE:
mp->ka_tx_cnt++;
break;
case PIM_MSDP_V4_SOURCE_ACTIVE:
mp->sa_tx_cnt++;
break;
default:;
}
if (PIM_DEBUG_MSDP_PACKETS) {
pim_msdp_pkt_dump(mp, type, len, false /*rx*/, s);
}
/* packet sent delete it. */
pim_msdp_pkt_delete(mp);
++work_cnt;
/* may need to pause if we have done too much work in this
* loop */
if (work_cnt >= work_max_cnt) {
break;
}
} while ((s = stream_fifo_head(mp->obuf)) != NULL);
pim_msdp_write_proceed_actions(mp);
sockopt_cork(mp->fd, 0);
if (PIM_DEBUG_MSDP_INTERNAL) {
zlog_debug("MSDP peer %s pim_msdp_write wrote %d packets", mp->key_str, work_cnt);
}
return 0;
}
static void
pim_msdp_pkt_send(struct pim_msdp_peer *mp, struct stream *s)
{
/* Add packet to the end of list. */
pim_msdp_pkt_add(mp, s);
PIM_MSDP_PEER_WRITE_ON(mp);
}
void
pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp)
{
struct stream *s;
if (mp->state != PIM_MSDP_ESTABLISHED) {
/* don't tx anything unless a session is established */
return;
}
s = stream_new(PIM_MSDP_KA_TLV_MAX_SIZE);
stream_putc(s, PIM_MSDP_KEEPALIVE);
stream_putw(s, PIM_MSDP_KA_TLV_MAX_SIZE);
pim_msdp_pkt_send(mp, s);
}
static void
pim_msdp_pkt_sa_push_to_one_peer(struct pim_msdp_peer *mp)
{
struct stream *s;
if (mp->state != PIM_MSDP_ESTABLISHED) {
/* don't tx anything unless a session is established */
return;
}
s = stream_dup(msdp->work_obuf);
if (s) {
pim_msdp_pkt_send(mp, s);
mp->flags |= PIM_MSDP_PEERF_SA_JUST_SENT;
}
}
/* push the stream into the obuf fifo of all the peers */
static void
pim_msdp_pkt_sa_push(struct pim_msdp_peer *mp)
{
struct listnode *mpnode;
if (mp) {
pim_msdp_pkt_sa_push_to_one_peer(mp);
} else {
for (ALL_LIST_ELEMENTS_RO(msdp->peer_list, mpnode, mp)) {
if (PIM_DEBUG_MSDP_INTERNAL) {
zlog_debug("MSDP peer %s pim_msdp_pkt_sa_push", mp->key_str);
}
pim_msdp_pkt_sa_push_to_one_peer(mp);
}
}
}
static int
pim_msdp_pkt_sa_fill_hdr(int local_cnt)
{
int curr_tlv_ecnt;
stream_reset(msdp->work_obuf);
curr_tlv_ecnt = local_cnt>PIM_MSDP_SA_MAX_ENTRY_CNT?PIM_MSDP_SA_MAX_ENTRY_CNT:local_cnt;
local_cnt -= curr_tlv_ecnt;
stream_putc(msdp->work_obuf, PIM_MSDP_V4_SOURCE_ACTIVE);
stream_putw(msdp->work_obuf, PIM_MSDP_SA_ENTRY_CNT2SIZE(curr_tlv_ecnt));
stream_putc(msdp->work_obuf, curr_tlv_ecnt);
stream_put_ipv4(msdp->work_obuf, msdp->originator_id.s_addr);
return local_cnt;
}
static void
pim_msdp_pkt_sa_fill_one(struct pim_msdp_sa *sa)
{
stream_put3(msdp->work_obuf, 0 /* reserved */);
stream_putc(msdp->work_obuf, 32 /* sprefix len */);
stream_put_ipv4(msdp->work_obuf, sa->sg.grp.s_addr);
stream_put_ipv4(msdp->work_obuf, sa->sg.src.s_addr);
}
static void
pim_msdp_pkt_sa_gen(struct pim_msdp_peer *mp)
{
struct listnode *sanode;
struct pim_msdp_sa *sa;
int sa_count;
int local_cnt = msdp->local_cnt;
sa_count = 0;
if (PIM_DEBUG_MSDP_INTERNAL) {
zlog_debug(" sa gen %d", local_cnt);
}
local_cnt = pim_msdp_pkt_sa_fill_hdr(local_cnt);
for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) {
if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) {
/* current implementation of MSDP is for anycast i.e. full mesh. so
* no re-forwarding of SAs that we learnt from other peers */
continue;
}
/* add sa into scratch pad */
pim_msdp_pkt_sa_fill_one(sa);
++sa_count;
if (sa_count >= PIM_MSDP_SA_MAX_ENTRY_CNT) {
pim_msdp_pkt_sa_push(mp);
/* reset headers */
sa_count = 0;
if (PIM_DEBUG_MSDP_INTERNAL) {
zlog_debug(" sa gen for remainder %d", local_cnt);
}
local_cnt = pim_msdp_pkt_sa_fill_hdr(local_cnt);
}
}
if (sa_count) {
pim_msdp_pkt_sa_push(mp);
}
return;
}
static void
pim_msdp_pkt_sa_tx_done(void)
{
struct listnode *mpnode;
struct pim_msdp_peer *mp;
/* if SA were sent to the peers we restart ka timer and avoid
* unnecessary ka noise */
for (ALL_LIST_ELEMENTS_RO(msdp->peer_list, mpnode, mp)) {
if (mp->flags & PIM_MSDP_PEERF_SA_JUST_SENT) {
mp->flags &= ~PIM_MSDP_PEERF_SA_JUST_SENT;
pim_msdp_peer_pkt_txed(mp);
}
}
}
void
pim_msdp_pkt_sa_tx(void)
{
pim_msdp_pkt_sa_gen(NULL /* mp */);
pim_msdp_pkt_sa_tx_done();
}
void
pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa)
{
pim_msdp_pkt_sa_fill_hdr(1 /* cnt */);
pim_msdp_pkt_sa_fill_one(sa);
pim_msdp_pkt_sa_push(NULL);
pim_msdp_pkt_sa_tx_done();
}
/* when a connection is first established we push all SAs immediately */
void
pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp)
{
pim_msdp_pkt_sa_gen(mp);
pim_msdp_pkt_sa_tx_done();
}
static void
pim_msdp_pkt_rxed_with_fatal_error(struct pim_msdp_peer *mp)
{
pim_msdp_peer_reset_tcp_conn(mp, "invalid-pkt-rx");
}
static void
pim_msdp_pkt_ka_rx(struct pim_msdp_peer *mp, int len)
{
mp->ka_rx_cnt++;
if (len != PIM_MSDP_KA_TLV_MAX_SIZE) {
pim_msdp_pkt_rxed_with_fatal_error(mp);
return;
}
pim_msdp_peer_pkt_rxed(mp);
}
static void
pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp)
{
int prefix_len;
struct prefix_sg sg;
/* just throw away the three reserved bytes */
stream_get3(mp->ibuf);
prefix_len = stream_getc(mp->ibuf);
memset(&sg, 0, sizeof (struct prefix_sg));
sg.grp.s_addr = stream_get_ipv4(mp->ibuf);
sg.src.s_addr = stream_get_ipv4(mp->ibuf);
if (prefix_len != 32) {
/* ignore SA update if the prefix length is not 32 */
zlog_err("rxed sa update with invalid prefix length %d", prefix_len);
return;
}
if (PIM_DEBUG_MSDP_PACKETS) {
zlog_debug(" sg %s", pim_str_sg_dump(&sg));
}
pim_msdp_sa_ref(mp, &sg, rp);
}
static void
pim_msdp_pkt_sa_rx(struct pim_msdp_peer *mp, int len)
{
int entry_cnt;
int i;
struct in_addr rp; /* Last RP address associated with this SA */
mp->sa_rx_cnt++;
if (len < PIM_MSDP_SA_TLV_MIN_SIZE) {
pim_msdp_pkt_rxed_with_fatal_error(mp);
return;
}
entry_cnt = stream_getc(mp->ibuf);
/* some vendors include the actual multicast data in the tlv (at the end).
* we will ignore such data. in the future we may consider pushing it down
* the RPT */
if (len < PIM_MSDP_SA_ENTRY_CNT2SIZE(entry_cnt)) {
pim_msdp_pkt_rxed_with_fatal_error(mp);
return;
}
rp.s_addr = stream_get_ipv4(mp->ibuf);
if (PIM_DEBUG_MSDP_PACKETS) {
char rp_str[INET_ADDRSTRLEN];
pim_inet4_dump("<rp?>", rp, rp_str, sizeof(rp_str));
zlog_debug(" entry_cnt %d rp %s", entry_cnt, rp_str);
}
if (!pim_msdp_peer_rpf_check(mp, rp)) {
/* if peer-RPF check fails don't process the packet any further */
if (PIM_DEBUG_MSDP_PACKETS) {
zlog_debug(" peer RPF check failed");
}
return;
}
pim_msdp_peer_pkt_rxed(mp);
/* update SA cache */
for (i = 0; i < entry_cnt; ++i) {
pim_msdp_pkt_sa_rx_one(mp, rp);
}
}
static void
pim_msdp_pkt_rx(struct pim_msdp_peer *mp)
{
enum pim_msdp_tlv type;
int len;
/* re-read type and len */
type = stream_getc_from(mp->ibuf, 0);
len = stream_getw_from(mp->ibuf, 1);
if (len < PIM_MSDP_HEADER_SIZE) {
pim_msdp_pkt_rxed_with_fatal_error(mp);
return;
}
if (len > PIM_MSDP_SA_TLV_MAX_SIZE) {
/* if tlv size if greater than max just ignore the tlv */
return;
}
if (PIM_DEBUG_MSDP_PACKETS) {
pim_msdp_pkt_dump(mp, type, len, true /*rx*/, NULL /*s*/);
}
switch(type) {
case PIM_MSDP_KEEPALIVE:
pim_msdp_pkt_ka_rx(mp, len);
break;
case PIM_MSDP_V4_SOURCE_ACTIVE:
mp->sa_rx_cnt++;
pim_msdp_pkt_sa_rx(mp, len);
break;
default:
mp->unk_rx_cnt++;
}
}
/* pim msdp read utility function. */
static int
pim_msdp_read_packet(struct pim_msdp_peer *mp)
{
int nbytes;
int readsize;
int old_endp;
int new_endp;
old_endp = stream_get_endp(mp->ibuf);
readsize = mp->packet_size - old_endp;
if (!readsize) {
return 0;
}
/* Read packet from fd */
nbytes = stream_read_try(mp->ibuf, mp->fd, readsize);
new_endp = stream_get_endp(mp->ibuf);
if (nbytes < 0) {
if (PIM_DEBUG_MSDP_INTERNAL) {
zlog_debug("MSDP peer %s read failed %d", mp->key_str, nbytes);
}
if (nbytes == -2) {
if (PIM_DEBUG_MSDP_INTERNAL) {
zlog_debug("MSDP peer %s pim_msdp_read io retry old_end: %d new_end: %d", mp->key_str, old_endp, new_endp);
}
/* transient error retry */
return -1;
}
pim_msdp_pkt_rxed_with_fatal_error(mp);
return -1;
}
if (!nbytes) {
if (PIM_DEBUG_MSDP_INTERNAL) {
zlog_debug("MSDP peer %s read failed %d", mp->key_str, nbytes);
}
pim_msdp_peer_reset_tcp_conn(mp, "peer-down");
return -1;
}
/* We read partial packet. */
if (stream_get_endp(mp->ibuf) != mp->packet_size) {
if (PIM_DEBUG_MSDP_INTERNAL) {
zlog_debug("MSDP peer %s read partial len %d old_endp %d new_endp %d", mp->key_str, mp->packet_size, old_endp, new_endp);
}
return -1;
}
return 0;
}
int
pim_msdp_read(struct thread *thread)
{
struct pim_msdp_peer *mp;
int rc;
uint32_t len;
mp = THREAD_ARG(thread);
mp->t_read = NULL;
if (PIM_DEBUG_MSDP_INTERNAL) {
zlog_debug("MSDP peer %s pim_msdp_read", mp->key_str);
}
if (mp->fd < 0) {
return -1;
}
/* check if TCP connection is established */
if (mp->state != PIM_MSDP_ESTABLISHED) {
pim_msdp_connect_check(mp);
return 0;
}
PIM_MSDP_PEER_READ_ON(mp);
if (!mp->packet_size) {
mp->packet_size = PIM_MSDP_HEADER_SIZE;
}
if (stream_get_endp(mp->ibuf) < PIM_MSDP_HEADER_SIZE) {
/* start by reading the TLV header */
rc = pim_msdp_read_packet(mp);
if (rc < 0) {
goto pim_msdp_read_end;
}
/* Find TLV type and len */
stream_getc(mp->ibuf);
len = stream_getw(mp->ibuf);
if (len < PIM_MSDP_HEADER_SIZE) {
pim_msdp_pkt_rxed_with_fatal_error(mp);
goto pim_msdp_read_end;
}
/* read complete TLV */
mp->packet_size = len;
}
rc = pim_msdp_read_packet(mp);
if (rc < 0) {
goto pim_msdp_read_end;
}
pim_msdp_pkt_rx(mp);
/* reset input buffers and get ready for the next packet */
mp->packet_size = 0;
stream_reset(mp->ibuf);
pim_msdp_read_end:
return 0;
}

72
pimd/pim_msdp_packet.h Normal file
View File

@ -0,0 +1,72 @@
/*
* IP MSDP packet helpers
* Copyright (C) 2016 Cumulus Networks, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifndef PIM_MSDP_PACKET_H
#define PIM_MSDP_PACKET_H
/* type and length of a single tlv can be consider packet header */
#define PIM_MSDP_HEADER_SIZE 3
/* Keepalive TLV
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 4 | 3 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
#define PIM_MSDP_KA_TLV_MAX_SIZE PIM_MSDP_HEADER_SIZE
/* Source-Active TLV (x=8, y=12xEntryCount)
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 1 | x + y | Entry Count |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| RP Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reserved | Sprefix Len | \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ \
| Group Address | ) z
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ /
| Source Address | /
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
#define PIM_MSDP_SA_TLV_MAX_SIZE 9192
#define PIM_MSDP_SA_X_SIZE 8
#define PIM_MSDP_SA_ONE_ENTRY_SIZE 12
#define PIM_MSDP_SA_Y_SIZE(entry_cnt) (PIM_MSDP_SA_ONE_ENTRY_SIZE * entry_cnt)
#define PIM_MSDP_SA_ENTRY_CNT2SIZE(entry_cnt) (PIM_MSDP_SA_X_SIZE +\
PIM_MSDP_SA_Y_SIZE(entry_cnt))
/* SA TLV has to have atleast only one entry in it so x=8 + y=12 */
#define PIM_MSDP_SA_TLV_MIN_SIZE PIM_MSDP_SA_ENTRY_CNT2SIZE(1)
/* XXX: theoretically we can fix a max of 255 but that may result in packet
* fragmentation */
#define PIM_MSDP_SA_MAX_ENTRY_CNT 120
#define PIM_MSDP_MAX_PACKET_SIZE max(PIM_MSDP_SA_TLV_MAX_SIZE, PIM_MSDP_KA_TLV_MAX_SIZE)
#define PIM_MSDP_PKT_TYPE_STRLEN 16
void pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp);
int pim_msdp_read(struct thread *thread);
void pim_msdp_pkt_sa_tx(void);
void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa);
void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp);
#endif

229
pimd/pim_msdp_socket.c Normal file
View File

@ -0,0 +1,229 @@
/*
* IP MSDP socket management
* Copyright (C) 2016 Cumulus Networks, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <zebra.h>
#include <lib/log.h>
#include <lib/network.h>
#include <lib/sockunion.h>
#include <lib/thread.h>
#include <lib/vty.h>
#include "pimd.h"
#include "pim_msdp.h"
#include "pim_msdp_socket.h"
extern struct zebra_privs_t pimd_privs;
/* increase socket send buffer size */
static void
pim_msdp_update_sock_send_buffer_size (int fd)
{
int size = PIM_MSDP_SOCKET_SNDBUF_SIZE;
int optval;
socklen_t optlen = sizeof(optval);
if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen) < 0) {
zlog_err("getsockopt of SO_SNDBUF failed %s\n", safe_strerror(errno));
return;
}
if (optval < size) {
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) < 0) {
zlog_err("Couldn't increase send buffer: %s\n", safe_strerror(errno));
}
}
}
/* passive peer socket accept */
static int
pim_msdp_sock_accept(struct thread *thread)
{
union sockunion su;
struct pim_msdp_listener *listener = THREAD_ARG(thread);
int accept_sock;
int msdp_sock;
struct pim_msdp_peer *mp;
char buf[SU_ADDRSTRLEN];
sockunion_init(&su);
/* re-register accept thread */
accept_sock = THREAD_FD(thread);
if (accept_sock < 0) {
zlog_err ("accept_sock is negative value %d", accept_sock);
return -1;
}
listener->thread = thread_add_read(master, pim_msdp_sock_accept,
listener, accept_sock);
/* accept client connection. */
msdp_sock = sockunion_accept(accept_sock, &su);
if (msdp_sock < 0) {
zlog_err ("pim_msdp_sock_accept failed (%s)", safe_strerror (errno));
return -1;
}
/* see if have peer config for this */
mp = pim_msdp_peer_find(su.sin.sin_addr);
if (!mp || !PIM_MSDP_PEER_IS_LISTENER(mp)) {
++msdp->rejected_accepts;
if (PIM_DEBUG_MSDP_EVENTS) {
zlog_err("msdp peer connection refused from %s",
sockunion2str(&su, buf, SU_ADDRSTRLEN));
}
close(msdp_sock);
return -1;
}
if (PIM_DEBUG_MSDP_INTERNAL) {
zlog_debug("MSDP peer %s accept success%s", mp->key_str, mp->fd>=0?"(dup)":"");
}
/* if we have an existing connection we need to kill that one
* with this one */
if (mp->fd >= 0) {
if (PIM_DEBUG_MSDP_EVENTS) {
zlog_err("msdp peer new connection from %s stop old connection",
sockunion2str(&su, buf, SU_ADDRSTRLEN));
}
pim_msdp_peer_stop_tcp_conn(mp, true /* chg_state */);
}
mp->fd = msdp_sock;
set_nonblocking(mp->fd);
pim_msdp_update_sock_send_buffer_size(mp->fd);
pim_msdp_peer_established(mp);
return 0;
}
/* global listener for the MSDP well know TCP port */
int
pim_msdp_sock_listen(void)
{
int sock;
int socklen;
struct sockaddr_in sin;
int rc;
struct pim_msdp_listener *listener = &msdp->listener;
if (msdp->flags & PIM_MSDPF_LISTENER) {
/* listener already setup */
return 0;
}
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
zlog_err ("socket: %s", safe_strerror (errno));
return sock;
}
memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_port = htons(PIM_MSDP_TCP_PORT);
socklen = sizeof(struct sockaddr_in);
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
sin.sin_len = socklen;
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
sockopt_reuseaddr(sock);
sockopt_reuseport(sock);
if (pimd_privs.change(ZPRIVS_RAISE)) {
zlog_err ("pim_msdp_socket: could not raise privs, %s",
safe_strerror (errno));
}
/* bind to well known TCP port */
rc = bind(sock, (struct sockaddr *)&sin, socklen);
if (pimd_privs.change(ZPRIVS_LOWER)) {
zlog_err ("pim_msdp_socket: could not lower privs, %s",
safe_strerror (errno));
}
if (rc < 0) {
zlog_err ("pim_msdp_socket bind to port %d: %s", ntohs(sin.sin_port), safe_strerror (errno));
close(sock);
return rc;
}
rc = listen(sock, 3 /* backlog */);
if (rc < 0) {
zlog_err ("pim_msdp_socket listen: %s", safe_strerror (errno));
close(sock);
return rc;
}
/* add accept thread */
listener->fd = sock;
memcpy(&listener->su, &sin, socklen);
listener->thread = thread_add_read(msdp->master, pim_msdp_sock_accept, listener, sock);
msdp->flags |= PIM_MSDPF_LISTENER;
return 0;
}
/* active peer socket setup */
int
pim_msdp_sock_connect(struct pim_msdp_peer *mp)
{
int rc;
if (PIM_DEBUG_MSDP_INTERNAL) {
zlog_debug("MSDP peer %s attempt connect%s", mp->key_str, mp->fd<0?"":"(dup)");
}
/* if we have an existing connection we need to kill that one
* with this one */
if (mp->fd >= 0) {
if (PIM_DEBUG_MSDP_EVENTS) {
zlog_err("msdp duplicate connect to %s nuke old connection", mp->key_str);
}
pim_msdp_peer_stop_tcp_conn(mp, false /* chg_state */);
}
/* Make socket for the peer. */
mp->fd = sockunion_socket(&mp->su_peer);
if (mp->fd < 0) {
zlog_err ("pim_msdp_socket socket failure: %s", safe_strerror (errno));
return -1;
}
set_nonblocking(mp->fd);
/* Set socket send buffer size */
pim_msdp_update_sock_send_buffer_size(mp->fd);
sockopt_reuseaddr(mp->fd);
sockopt_reuseport(mp->fd);
/* source bind */
rc = sockunion_bind(mp->fd, &mp->su_local, 0, &mp->su_local);
if (rc < 0) {
zlog_err ("pim_msdp_socket connect bind failure: %s", safe_strerror (errno));
close(mp->fd);
mp->fd = -1;
return rc;
}
/* Connect to the remote mp. */
return (sockunion_connect(mp->fd, &mp->su_peer, htons(PIM_MSDP_TCP_PORT), 0));
}

25
pimd/pim_msdp_socket.h Normal file
View File

@ -0,0 +1,25 @@
/*
* IP MSDP socket management for Quagga
* Copyright (C) 2016 Cumulus Networks, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifndef PIM_MSDP_SOCKET_H
#define PIM_MSDP_SOCKET_H
int pim_msdp_sock_listen(void);
int pim_msdp_sock_connect(struct pim_msdp_peer *mp);
#endif

View File

@ -21,11 +21,20 @@
#include <zebra.h> #include <zebra.h>
#include "if.h" #include "if.h"
#include "log.h"
#include "prefix.h"
#include "vty.h"
#include "plist.h"
#include "pimd.h" #include "pimd.h"
#include "pim_vty.h"
#include "pim_pim.h" #include "pim_pim.h"
#include "pim_msg.h" #include "pim_msg.h"
#include "pim_util.h" #include "pim_util.h"
#include "pim_str.h"
#include "pim_iface.h"
#include "pim_rp.h"
#include "pim_rpf.h"
void pim_msg_build_header(uint8_t *pim_msg, int pim_msg_size, void pim_msg_build_header(uint8_t *pim_msg, int pim_msg_size,
uint8_t pim_msg_type) uint8_t pim_msg_type)
@ -86,9 +95,9 @@ uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf,
return buf + ENCODED_IPV4_GROUP_SIZE; return buf + ENCODED_IPV4_GROUP_SIZE;
} }
uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf, uint8_t *
int buf_size, pim_msg_addr_encode_ipv4_source(uint8_t *buf, int buf_size,
struct in_addr addr) struct in_addr addr, uint8_t bits)
{ {
const int ENCODED_IPV4_SOURCE_SIZE = 8; const int ENCODED_IPV4_SOURCE_SIZE = 8;
@ -98,9 +107,172 @@ uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf,
buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */
buf[1] = '\0'; /* native encoding */ buf[1] = '\0'; /* native encoding */
buf[2] = 4; /* reserved = 0 | S bit = 1 | W bit = 0 | R bit = 0 */ buf[2] = bits;
buf[3] = 32; /* mask len */ buf[3] = 32; /* mask len */
memcpy(buf+4, &addr, sizeof(struct in_addr)); memcpy(buf+4, &addr, sizeof(struct in_addr));
return buf + ENCODED_IPV4_SOURCE_SIZE; return buf + ENCODED_IPV4_SOURCE_SIZE;
} }
int
pim_msg_join_prune_encode (uint8_t *buf, int buf_size, int is_join,
struct pim_upstream *up,
struct in_addr upstream, int holdtime)
{
uint8_t *pim_msg = buf;
uint8_t *pim_msg_curr = buf + PIM_MSG_HEADER_LEN;
uint8_t *end = buf + buf_size;
uint16_t *prunes = NULL;
uint16_t *joins = NULL;
struct in_addr stosend;
uint8_t bits;
int remain;
remain = end - pim_msg_curr;
pim_msg_curr = pim_msg_addr_encode_ipv4_ucast (pim_msg_curr, buf_size - PIM_MSG_HEADER_LEN, upstream);
if (!pim_msg_curr) {
char dst_str[INET_ADDRSTRLEN];
pim_inet4_dump("<dst?>", upstream, dst_str, sizeof(dst_str));
zlog_warn("%s: failure encoding destination address %s: space left=%d",
__PRETTY_FUNCTION__, dst_str, remain);
return -3;
}
remain = end - pim_msg_curr;
if (remain < 4) {
zlog_warn("%s: group will not fit: space left=%d",
__PRETTY_FUNCTION__, remain);
return -4;
}
*pim_msg_curr = 0; /* reserved */
++pim_msg_curr;
*pim_msg_curr = 1; /* number of groups */
++pim_msg_curr;
*((uint16_t *) pim_msg_curr) = htons(holdtime);
++pim_msg_curr;
++pim_msg_curr;
remain = end - pim_msg_curr;
pim_msg_curr = pim_msg_addr_encode_ipv4_group (pim_msg_curr, remain,
up->sg.grp);
if (!pim_msg_curr) {
char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", up->sg.grp, group_str, sizeof(group_str));
zlog_warn("%s: failure encoding group address %s: space left=%d",
__PRETTY_FUNCTION__, group_str, remain);
return -5;
}
remain = end - pim_msg_curr;
if (remain < 4) {
zlog_warn("%s: sources will not fit: space left=%d",
__PRETTY_FUNCTION__, remain);
return -6;
}
/* number of joined sources */
joins = (uint16_t *)pim_msg_curr;
*joins = htons(is_join ? 1 : 0);
++pim_msg_curr;
++pim_msg_curr;
/* number of pruned sources */
prunes = (uint16_t *)pim_msg_curr;
*prunes = htons(is_join ? 0 : 1);
++pim_msg_curr;
++pim_msg_curr;
remain = end - pim_msg_curr;
if (up->sg.src.s_addr == INADDR_ANY)
{
struct pim_rpf *rpf = pim_rp_g (up->sg.grp);
bits = PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_WC_BIT | PIM_ENCODE_RPT_BIT;
stosend = rpf->rpf_addr.u.prefix4;
}
else
{
bits = PIM_ENCODE_SPARSE_BIT;
stosend = up->sg.src;
}
pim_msg_curr = pim_msg_addr_encode_ipv4_source (pim_msg_curr, remain, stosend, bits);
if (!pim_msg_curr) {
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", up->sg.src, source_str, sizeof(source_str));
zlog_warn("%s: failure encoding source address %s: space left=%d",
__PRETTY_FUNCTION__, source_str, remain);
return -7;
}
remain = pim_msg_curr - pim_msg;
/*
* This is not implemented correctly at this point in time
* Make it stop.
*/
#if 0
if (up->sg.src.s_addr == INADDR_ANY)
{
struct pim_upstream *child;
struct listnode *up_node;
int send_prune = 0;
zlog_debug ("%s: Considering (%s) children for (S,G,rpt) prune",
__PRETTY_FUNCTION__, up->sg_str);
for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
{
if (child->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
{
if (!pim_rpf_is_same(&up->rpf, &child->rpf))
{
send_prune = 1;
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug ("%s: SPT Bit and RPF'(%s) != RPF'(S,G): Add Prune (%s,rpt) to compound message",
__PRETTY_FUNCTION__, up->sg_str, child->sg_str);
}
else
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug ("%s: SPT Bit and RPF'(%s) == RPF'(S,G): Not adding Prune for (%s,rpt)",
__PRETTY_FUNCTION__, up->sg_str, child->sg_str);
}
else if (pim_upstream_is_sg_rpt (child))
{
if (pim_upstream_empty_inherited_olist (child))
{
send_prune = 1;
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug ("%s: inherited_olist(%s,rpt) is NULL, Add Prune to compound message",
__PRETTY_FUNCTION__, child->sg_str);
}
else if (!pim_rpf_is_same (&up->rpf, &child->rpf))
{
send_prune = 1;
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug ("%s: RPF'(%s) != RPF'(%s,rpt), Add Prune to compound message",
__PRETTY_FUNCTION__, up->sg_str, child->sg_str);
}
else
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug ("%s: RPF'(%s) == RPF'(%s,rpt), Do not add Prune to compound message",
__PRETTY_FUNCTION__, up->sg_str, child->sg_str);
}
else
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug ("%s: SPT bit is not set for (%s)",
__PRETTY_FUNCTION__, child->sg_str);
if (send_prune)
{
pim_msg_curr = pim_msg_addr_encode_ipv4_source (pim_msg_curr, remain,
child->sg.src,
PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_RPT_BIT);
remain = pim_msg_curr - pim_msg;
*prunes = htons(ntohs(*prunes) + 1);
send_prune = 0;
}
}
}
#endif
pim_msg_build_header (pim_msg, remain, PIM_MSG_TYPE_JOIN_PRUNE);
return remain;
}

View File

@ -43,8 +43,17 @@ uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf,
uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf,
int buf_size, int buf_size,
struct in_addr addr); struct in_addr addr);
#define PIM_ENCODE_SPARSE_BIT 0x04
#define PIM_ENCODE_WC_BIT 0x02
#define PIM_ENCODE_RPT_BIT 0x01
uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf, uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf,
int buf_size, int buf_size,
struct in_addr addr); struct in_addr addr,
uint8_t bits);
int pim_msg_join_prune_encode (uint8_t *buf, int buf_size, int is_join,
struct pim_upstream *up,
struct in_addr upstream, int holdtime);
#endif /* PIM_MSG_H */ #endif /* PIM_MSG_H */

View File

@ -24,6 +24,8 @@
#include "prefix.h" #include "prefix.h"
#include "memory.h" #include "memory.h"
#include "if.h" #include "if.h"
#include "vty.h"
#include "plist.h"
#include "pimd.h" #include "pimd.h"
#include "pim_neighbor.h" #include "pim_neighbor.h"
@ -33,6 +35,8 @@
#include "pim_pim.h" #include "pim_pim.h"
#include "pim_upstream.h" #include "pim_upstream.h"
#include "pim_ifchannel.h" #include "pim_ifchannel.h"
#include "pim_rp.h"
#include "pim_zebra.h"
static void dr_election_by_addr(struct interface *ifp) static void dr_election_by_addr(struct interface *ifp)
{ {
@ -125,8 +129,8 @@ int pim_if_dr_election(struct interface *ifp)
if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) { if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) {
if (PIM_DEBUG_PIM_EVENTS) { if (PIM_DEBUG_PIM_EVENTS) {
char dr_old_str[100]; char dr_old_str[INET_ADDRSTRLEN];
char dr_new_str[100]; char dr_new_str[INET_ADDRSTRLEN];
pim_inet4_dump("<old_dr?>", old_dr_addr, dr_old_str, sizeof(dr_old_str)); pim_inet4_dump("<old_dr?>", old_dr_addr, dr_old_str, sizeof(dr_old_str));
pim_inet4_dump("<new_dr?>", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str)); pim_inet4_dump("<new_dr?>", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str));
zlog_debug("%s: DR was %s now is %s on interface %s", zlog_debug("%s: DR was %s now is %s on interface %s",
@ -207,20 +211,18 @@ static int on_neighbor_timer(struct thread *t)
struct interface *ifp; struct interface *ifp;
char msg[100]; char msg[100];
zassert(t);
neigh = THREAD_ARG(t); neigh = THREAD_ARG(t);
zassert(neigh);
ifp = neigh->interface; ifp = neigh->interface;
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_TRACE) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
zlog_debug("Expired %d sec holdtime for neighbor %s on interface %s", zlog_debug("Expired %d sec holdtime for neighbor %s on interface %s",
neigh->holdtime, src_str, ifp->name); neigh->holdtime, src_str, ifp->name);
} }
neigh->t_expire_timer = 0; neigh->t_expire_timer = NULL;
snprintf(msg, sizeof(msg), "%d-sec holdtime expired", neigh->holdtime); snprintf(msg, sizeof(msg), "%d-sec holdtime expired", neigh->holdtime);
pim_neighbor_delete(ifp, neigh, msg); pim_neighbor_delete(ifp, neigh, msg);
@ -237,26 +239,11 @@ static int on_neighbor_timer(struct thread *t)
return 0; return 0;
} }
static void neighbor_timer_off(struct pim_neighbor *neigh)
{
if (PIM_DEBUG_PIM_TRACE_DETAIL) {
if (neigh->t_expire_timer) {
char src_str[100];
pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
zlog_debug("%s: cancelling timer for neighbor %s on %s",
__PRETTY_FUNCTION__,
src_str, neigh->interface->name);
}
}
THREAD_OFF(neigh->t_expire_timer);
zassert(!neigh->t_expire_timer);
}
void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime) void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime)
{ {
neigh->holdtime = holdtime; neigh->holdtime = holdtime;
neighbor_timer_off(neigh); THREAD_OFF(neigh->t_expire_timer);
/* /*
0xFFFF is request for no holdtime 0xFFFF is request for no holdtime
@ -266,7 +253,7 @@ void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime)
} }
if (PIM_DEBUG_PIM_TRACE_DETAIL) { if (PIM_DEBUG_PIM_TRACE_DETAIL) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
zlog_debug("%s: starting %u sec timer for neighbor %s on %s", zlog_debug("%s: starting %u sec timer for neighbor %s on %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -290,15 +277,15 @@ static struct pim_neighbor *pim_neighbor_new(struct interface *ifp,
{ {
struct pim_interface *pim_ifp; struct pim_interface *pim_ifp;
struct pim_neighbor *neigh; struct pim_neighbor *neigh;
char src_str[100]; char src_str[INET_ADDRSTRLEN];
zassert(ifp); zassert(ifp);
pim_ifp = ifp->info; pim_ifp = ifp->info;
zassert(pim_ifp); zassert(pim_ifp);
neigh = XMALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh)); neigh = XCALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh));
if (!neigh) { if (!neigh) {
zlog_err("%s: PIM XMALLOC(%zu) failure", zlog_err("%s: PIM XCALLOC(%zu) failure",
__PRETTY_FUNCTION__, sizeof(*neigh)); __PRETTY_FUNCTION__, sizeof(*neigh));
return 0; return 0;
} }
@ -311,10 +298,18 @@ static struct pim_neighbor *pim_neighbor_new(struct interface *ifp,
neigh->dr_priority = dr_priority; neigh->dr_priority = dr_priority;
neigh->generation_id = generation_id; neigh->generation_id = generation_id;
neigh->prefix_list = addr_list; neigh->prefix_list = addr_list;
neigh->t_expire_timer = 0; neigh->t_expire_timer = NULL;
neigh->interface = ifp; neigh->interface = ifp;
pim_neighbor_timer_reset(neigh, holdtime); pim_neighbor_timer_reset(neigh, holdtime);
/*
* The pim_ifstat_hello_sent variable is used to decide if
* we should expedite a hello out the interface. If we
* establish a new neighbor, we unfortunately need to
* reset the value so that we can know to hurry up and
* hello
*/
pim_ifp->pim_ifstat_hello_sent = 0;
pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
@ -391,7 +386,8 @@ struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
struct pim_neighbor *neigh; struct pim_neighbor *neigh;
pim_ifp = ifp->info; pim_ifp = ifp->info;
zassert(pim_ifp); if (!pim_ifp)
return NULL;
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
if (source_addr.s_addr == neigh->source_addr.s_addr) { if (source_addr.s_addr == neigh->source_addr.s_addr) {
@ -399,7 +395,35 @@ struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
} }
} }
return 0; return NULL;
}
/*
* Find the *one* interface out
* this interface. If more than
* one return NULL
*/
struct pim_neighbor *
pim_neighbor_find_if (struct interface *ifp)
{
struct pim_interface *pim_ifp = ifp->info;
if (!pim_ifp || pim_ifp->pim_neighbor_list->count != 1)
return NULL;
return listnode_head (pim_ifp->pim_neighbor_list);
}
/* rpf info associated with an upstream entry needs to be re-evaluated
* when an RPF neighbor comes or goes */
static void
pim_neighbor_rpf_update(void)
{
/* XXX: for the time being piggyback on the timer used on rib changes
* to scan and update the rpf nexthop. This is expensive processing
* and we should be able to optimize neighbor changes differently than
* nexthop changes. */
sched_rpf_cache_refresh();
} }
struct pim_neighbor *pim_neighbor_add(struct interface *ifp, struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
@ -410,7 +434,8 @@ struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
uint16_t override_interval, uint16_t override_interval,
uint32_t dr_priority, uint32_t dr_priority,
uint32_t generation_id, uint32_t generation_id,
struct list *addr_list) struct list *addr_list,
int send_hello_now)
{ {
struct pim_interface *pim_ifp; struct pim_interface *pim_ifp;
struct pim_neighbor *neigh; struct pim_neighbor *neigh;
@ -449,9 +474,22 @@ struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
message with a new GenID is received from an existing neighbor, a message with a new GenID is received from an existing neighbor, a
new Hello message should be sent on this interface after a new Hello message should be sent on this interface after a
randomized delay between 0 and Triggered_Hello_Delay. randomized delay between 0 and Triggered_Hello_Delay.
*/
pim_hello_restart_triggered(neigh->interface);
This is a bit silly to do it that way. If I get a new
genid we need to send the hello *now* because we've
lined up a bunch of join/prune messages to go out the
interface.
*/
if (send_hello_now)
pim_hello_restart_now (ifp);
else
pim_hello_restart_triggered(neigh->interface);
pim_upstream_find_new_rpf();
pim_rp_setup ();
pim_neighbor_rpf_update();
return neigh; return neigh;
} }
@ -508,7 +546,7 @@ void pim_neighbor_delete(struct interface *ifp,
const char *delete_message) const char *delete_message)
{ {
struct pim_interface *pim_ifp; struct pim_interface *pim_ifp;
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_ifp = ifp->info; pim_ifp = ifp->info;
zassert(pim_ifp); zassert(pim_ifp);
@ -517,7 +555,7 @@ void pim_neighbor_delete(struct interface *ifp,
zlog_info("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s", zlog_info("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s",
src_str, ifp->name, delete_message); src_str, ifp->name, delete_message);
neighbor_timer_off(neigh); THREAD_OFF(neigh->t_expire_timer);
pim_if_assert_on_neighbor_down(ifp, neigh->source_addr); pim_if_assert_on_neighbor_down(ifp, neigh->source_addr);
@ -564,6 +602,8 @@ void pim_neighbor_delete(struct interface *ifp,
listnode_delete(pim_ifp->pim_neighbor_list, neigh); listnode_delete(pim_ifp->pim_neighbor_list, neigh);
pim_neighbor_free(neigh); pim_neighbor_free(neigh);
pim_neighbor_rpf_update();
} }
void pim_neighbor_delete_all(struct interface *ifp, void pim_neighbor_delete_all(struct interface *ifp,
@ -646,9 +686,9 @@ static void delete_from_neigh_addr(struct interface *ifp,
{ {
struct prefix *p = pim_neighbor_find_secondary(neigh, addr->u.prefix4); struct prefix *p = pim_neighbor_find_secondary(neigh, addr->u.prefix4);
if (p) { if (p) {
char addr_str[100]; char addr_str[INET_ADDRSTRLEN];
char this_neigh_str[100]; char this_neigh_str[INET_ADDRSTRLEN];
char other_neigh_str[100]; char other_neigh_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr->u.prefix4, addr_str, sizeof(addr_str)); pim_inet4_dump("<addr?>", addr->u.prefix4, addr_str, sizeof(addr_str));
pim_inet4_dump("<neigh1?>", neigh_addr, this_neigh_str, sizeof(this_neigh_str)); pim_inet4_dump("<neigh1?>", neigh_addr, this_neigh_str, sizeof(this_neigh_str));

View File

@ -25,6 +25,7 @@
#include "if.h" #include "if.h"
#include "linklist.h" #include "linklist.h"
#include "prefix.h"
#include "pim_tlv.h" #include "pim_tlv.h"
@ -46,6 +47,12 @@ void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime);
void pim_neighbor_free(struct pim_neighbor *neigh); void pim_neighbor_free(struct pim_neighbor *neigh);
struct pim_neighbor *pim_neighbor_find(struct interface *ifp, struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
struct in_addr source_addr); struct in_addr source_addr);
struct pim_neighbor *pim_neighbor_find_if (struct interface *ifp);
#define PIM_NEIGHBOR_SEND_DELAY 0
#define PIM_NEIGHBOR_SEND_NOW 1
struct pim_neighbor *pim_neighbor_add(struct interface *ifp, struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
struct in_addr source_addr, struct in_addr source_addr,
pim_hello_options hello_options, pim_hello_options hello_options,
@ -54,7 +61,8 @@ struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
uint16_t override_interval, uint16_t override_interval,
uint32_t dr_priority, uint32_t dr_priority,
uint32_t generation_id, uint32_t generation_id,
struct list *addr_list); struct list *addr_list,
int send_hello_now);
void pim_neighbor_delete(struct interface *ifp, void pim_neighbor_delete(struct interface *ifp,
struct pim_neighbor *neigh, struct pim_neighbor *neigh,
const char *delete_message); const char *delete_message);

View File

@ -24,6 +24,8 @@
#include "memory.h" #include "memory.h"
#include "linklist.h" #include "linklist.h"
#include "if.h" #include "if.h"
#include "hash.h"
#include "jhash.h"
#include "pimd.h" #include "pimd.h"
#include "pim_oil.h" #include "pim_oil.h"
@ -31,104 +33,162 @@
#include "pim_iface.h" #include "pim_iface.h"
#include "pim_time.h" #include "pim_time.h"
struct list *pim_channel_oil_list = NULL;
struct hash *pim_channel_oil_hash = NULL;
static int
pim_channel_oil_compare (struct channel_oil *c1, struct channel_oil *c2)
{
if (ntohl(c1->oil.mfcc_mcastgrp.s_addr) < ntohl(c2->oil.mfcc_mcastgrp.s_addr))
return -1;
if (ntohl(c1->oil.mfcc_mcastgrp.s_addr) > ntohl(c2->oil.mfcc_mcastgrp.s_addr))
return 1;
if (ntohl(c1->oil.mfcc_origin.s_addr) < ntohl(c2->oil.mfcc_origin.s_addr))
return -1;
if (ntohl(c1->oil.mfcc_origin.s_addr) > ntohl(c2->oil.mfcc_origin.s_addr))
return 1;
return 0;
}
static int
pim_oil_equal (const void *arg1, const void *arg2)
{
const struct channel_oil *c1 = (const struct channel_oil *)arg1;
const struct channel_oil *c2 = (const struct channel_oil *)arg2;
if ((c1->oil.mfcc_mcastgrp.s_addr == c2->oil.mfcc_mcastgrp.s_addr) &&
(c1->oil.mfcc_origin.s_addr == c2->oil.mfcc_origin.s_addr))
return 1;
return 0;
}
static unsigned int
pim_oil_hash_key (void *arg)
{
struct channel_oil *oil = (struct channel_oil *)arg;
return jhash_2words (oil->oil.mfcc_mcastgrp.s_addr, oil->oil.mfcc_origin.s_addr, 0);
}
void
pim_oil_init (void)
{
pim_channel_oil_hash = hash_create_size (8192, pim_oil_hash_key,
pim_oil_equal);
pim_channel_oil_list = list_new();
if (!pim_channel_oil_list) {
zlog_err("%s %s: failure: channel_oil_list=list_new()",
__FILE__, __PRETTY_FUNCTION__);
return;
}
pim_channel_oil_list->del = (void (*)(void *)) pim_channel_oil_free;
pim_channel_oil_list->cmp = (int (*)(void *, void *)) pim_channel_oil_compare;
}
void
pim_oil_terminate (void)
{
if (pim_channel_oil_list)
list_free(pim_channel_oil_list);
pim_channel_oil_list = NULL;
if (pim_channel_oil_hash)
hash_free (pim_channel_oil_hash);
pim_channel_oil_hash = NULL;
}
void pim_channel_oil_free(struct channel_oil *c_oil) void pim_channel_oil_free(struct channel_oil *c_oil)
{ {
XFREE(MTYPE_PIM_CHANNEL_OIL, c_oil); XFREE(MTYPE_PIM_CHANNEL_OIL, c_oil);
} }
static void pim_channel_oil_delete(struct channel_oil *c_oil) static void
pim_del_channel_oil (struct channel_oil *c_oil)
{ {
/* /*
notice that listnode_delete() can't be moved notice that listnode_delete() can't be moved
into pim_channel_oil_free() because the later is into pim_channel_oil_free() because the later is
called by list_delete_all_node() called by list_delete_all_node()
*/ */
listnode_delete(qpim_channel_oil_list, c_oil); listnode_delete(pim_channel_oil_list, c_oil);
hash_release (pim_channel_oil_hash, c_oil);
pim_channel_oil_free(c_oil); pim_channel_oil_free(c_oil);
} }
static struct channel_oil *channel_oil_new(struct in_addr group_addr, static struct channel_oil *
struct in_addr source_addr, pim_add_channel_oil (struct prefix_sg *sg,
int input_vif_index) int input_vif_index)
{ {
struct channel_oil *c_oil; struct channel_oil *c_oil;
struct interface *ifp_in; struct interface *ifp;
ifp_in = pim_if_find_by_vif_index(input_vif_index); ifp = pim_if_find_by_vif_index(input_vif_index);
if (!ifp_in) { if (!ifp) {
/* warning only */ /* warning only */
char group_str[100]; zlog_warn("%s: (S,G)=%s could not find input interface for input_vif_index=%d",
char source_str[100];
pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: (S,G)=(%s,%s) could not find input interface for input_vif_index=%d",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
source_str, group_str, input_vif_index); pim_str_sg_dump (sg), input_vif_index);
} }
c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil)); c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil));
if (!c_oil) { if (!c_oil) {
zlog_err("PIM XCALLOC(%zu) failure", sizeof(*c_oil)); zlog_err("PIM XCALLOC(%zu) failure", sizeof(*c_oil));
return 0; return NULL;
} }
c_oil->oil.mfcc_mcastgrp = group_addr; c_oil->oil.mfcc_mcastgrp = sg->grp;
c_oil->oil.mfcc_origin = source_addr; c_oil->oil.mfcc_origin = sg->src;
c_oil = hash_get (pim_channel_oil_hash, c_oil, hash_alloc_intern);
c_oil->oil.mfcc_parent = input_vif_index; c_oil->oil.mfcc_parent = input_vif_index;
c_oil->oil_ref_count = 1; c_oil->oil_ref_count = 1;
c_oil->installed = 0; c_oil->installed = 0;
zassert(c_oil->oil_size == 0); listnode_add_sort(pim_channel_oil_list, c_oil);
return c_oil; return c_oil;
} }
static struct channel_oil *pim_add_channel_oil(struct in_addr group_addr, static struct channel_oil *pim_find_channel_oil(struct prefix_sg *sg)
struct in_addr source_addr,
int input_vif_index)
{ {
struct channel_oil *c_oil; struct channel_oil *c_oil = NULL;
struct channel_oil lookup;
c_oil = channel_oil_new(group_addr, source_addr, input_vif_index); lookup.oil.mfcc_mcastgrp = sg->grp;
if (!c_oil) { lookup.oil.mfcc_origin = sg->src;
zlog_warn("PIM XCALLOC(%zu) failure", sizeof(*c_oil));
return 0;
}
listnode_add(qpim_channel_oil_list, c_oil); c_oil = hash_lookup (pim_channel_oil_hash, &lookup);
return c_oil; return c_oil;
} }
static struct channel_oil *pim_find_channel_oil(struct in_addr group_addr, struct channel_oil *pim_channel_oil_add(struct prefix_sg *sg,
struct in_addr source_addr)
{
struct listnode *node;
struct channel_oil *c_oil;
for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) {
if ((group_addr.s_addr == c_oil->oil.mfcc_mcastgrp.s_addr) &&
(source_addr.s_addr == c_oil->oil.mfcc_origin.s_addr))
return c_oil;
}
return 0;
}
struct channel_oil *pim_channel_oil_add(struct in_addr group_addr,
struct in_addr source_addr,
int input_vif_index) int input_vif_index)
{ {
struct channel_oil *c_oil; struct channel_oil *c_oil;
c_oil = pim_find_channel_oil(group_addr, source_addr); c_oil = pim_find_channel_oil(sg);
if (c_oil) { if (c_oil) {
if (c_oil->oil.mfcc_parent != input_vif_index)
{
c_oil->oil_inherited_rescan = 1;
if (PIM_DEBUG_MROUTE)
zlog_debug ("%s: Existing channel oil %s points to %d, modifying to point at %d",
__PRETTY_FUNCTION__, pim_str_sg_dump(sg), c_oil->oil.mfcc_parent, input_vif_index);
}
c_oil->oil.mfcc_parent = input_vif_index;
++c_oil->oil_ref_count; ++c_oil->oil_ref_count;
return c_oil; return c_oil;
} }
return pim_add_channel_oil(group_addr, source_addr, input_vif_index); return pim_add_channel_oil(sg, input_vif_index);
} }
void pim_channel_oil_del(struct channel_oil *c_oil) void pim_channel_oil_del(struct channel_oil *c_oil)
@ -136,10 +196,96 @@ void pim_channel_oil_del(struct channel_oil *c_oil)
--c_oil->oil_ref_count; --c_oil->oil_ref_count;
if (c_oil->oil_ref_count < 1) { if (c_oil->oil_ref_count < 1) {
pim_channel_oil_delete(c_oil); pim_del_channel_oil(c_oil);
} }
} }
int
pim_channel_del_oif (struct channel_oil *channel_oil,
struct interface *oif,
uint32_t proto_mask)
{
struct pim_interface *pim_ifp;
zassert (channel_oil);
zassert (oif);
pim_ifp = oif->info;
/*
* Don't do anything if we've been asked to remove a source
* that is not actually on it.
*/
if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask))
{
if (PIM_DEBUG_MROUTE)
{
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: no existing protocol mask %u(%u) for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
__FILE__, __PRETTY_FUNCTION__,
proto_mask, channel_oil->oif_flags[pim_ifp->mroute_vif_index],
oif->name, pim_ifp->mroute_vif_index,
channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
source_str, group_str);
}
return 0;
}
channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
if (channel_oil->oif_flags[pim_ifp->mroute_vif_index])
{
if (PIM_DEBUG_MROUTE)
{
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: other protocol masks remain for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
__FILE__, __PRETTY_FUNCTION__,
oif->name, pim_ifp->mroute_vif_index,
channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
source_str, group_str);
}
return 0;
}
channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
if (pim_mroute_add (channel_oil, __PRETTY_FUNCTION__)) {
if (PIM_DEBUG_MROUTE)
{
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: could not remove output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
__FILE__, __PRETTY_FUNCTION__,
oif->name, pim_ifp->mroute_vif_index,
source_str, group_str);
}
return -1;
}
if (PIM_DEBUG_MROUTE)
{
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
__FILE__, __PRETTY_FUNCTION__,
source_str, group_str,
proto_mask, oif->name, pim_ifp->mroute_vif_index);
}
return 0;
}
int pim_channel_add_oif(struct channel_oil *channel_oil, int pim_channel_add_oif(struct channel_oil *channel_oil,
struct interface *oif, struct interface *oif,
uint32_t proto_mask) uint32_t proto_mask)
@ -147,21 +293,18 @@ int pim_channel_add_oif(struct channel_oil *channel_oil,
struct pim_interface *pim_ifp; struct pim_interface *pim_ifp;
int old_ttl; int old_ttl;
zassert(channel_oil); /*
* If we've gotten here we've gone bad, but let's
* not take down pim
*/
if (!channel_oil)
{
zlog_warn ("Attempt to Add OIF for non-existent channel oil");
return -1;
}
pim_ifp = oif->info; pim_ifp = oif->info;
if (PIM_DEBUG_MROUTE) {
char group_str[100];
char source_str[100];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
__FILE__, __PRETTY_FUNCTION__,
source_str, group_str,
proto_mask, oif->name, pim_ifp->mroute_vif_index);
}
#ifdef PIM_ENFORCE_LOOPFREE_MFC #ifdef PIM_ENFORCE_LOOPFREE_MFC
/* /*
Prevent creating MFC entry with OIF=IIF. Prevent creating MFC entry with OIF=IIF.
@ -175,10 +318,11 @@ int pim_channel_add_oif(struct channel_oil *channel_oil,
TODO T22. TODO T22.
*/ */
if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) { if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
channel_oil->oil_inherited_rescan = 1;
if (PIM_DEBUG_MROUTE) if (PIM_DEBUG_MROUTE)
{ {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)", zlog_debug("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
@ -195,8 +339,8 @@ int pim_channel_add_oif(struct channel_oil *channel_oil,
if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) { if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
if (PIM_DEBUG_MROUTE) if (PIM_DEBUG_MROUTE)
{ {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)", zlog_debug("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
@ -218,8 +362,8 @@ int pim_channel_add_oif(struct channel_oil *channel_oil,
if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) { if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
if (PIM_DEBUG_MROUTE) if (PIM_DEBUG_MROUTE)
{ {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)", zlog_debug("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
@ -238,8 +382,8 @@ int pim_channel_add_oif(struct channel_oil *channel_oil,
if (old_ttl > 0) { if (old_ttl > 0) {
if (PIM_DEBUG_MROUTE) if (PIM_DEBUG_MROUTE)
{ {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)", zlog_debug("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
@ -252,11 +396,11 @@ int pim_channel_add_oif(struct channel_oil *channel_oil,
channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL; channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;
if (pim_mroute_add(channel_oil)) { if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) {
if (PIM_DEBUG_MROUTE) if (PIM_DEBUG_MROUTE)
{ {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)", zlog_debug("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
@ -274,8 +418,8 @@ int pim_channel_add_oif(struct channel_oil *channel_oil,
channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask; channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
if (PIM_DEBUG_MROUTE) { if (PIM_DEBUG_MROUTE) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE", zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
@ -286,3 +430,24 @@ int pim_channel_add_oif(struct channel_oil *channel_oil,
return 0; return 0;
} }
int
pim_channel_oil_empty (struct channel_oil *c_oil)
{
static uint32_t zero[MAXVIFS];
static int inited = 0;
if (!c_oil)
return 1;
/*
* Not sure that this is necessary, but I would rather ensure
* that this works.
*/
if (!inited)
{
memset(&zero, 0, sizeof(uint32_t) * MAXVIFS);
inited = 1;
}
return !memcmp(c_oil->oif_flags, zero, MAXVIFS * sizeof(uint32_t));
}

View File

@ -51,6 +51,7 @@
struct channel_counts struct channel_counts
{ {
unsigned long long lastused;
unsigned long pktcnt; unsigned long pktcnt;
unsigned long oldpktcnt; unsigned long oldpktcnt;
unsigned long bytecnt; unsigned long bytecnt;
@ -69,6 +70,7 @@ struct channel_counts
struct channel_oil { struct channel_oil {
struct mfcctl oil; struct mfcctl oil;
int installed; int installed;
int oil_inherited_rescan;
int oil_size; int oil_size;
int oil_ref_count; int oil_ref_count;
time_t oif_creation[MAXVIFS]; time_t oif_creation[MAXVIFS];
@ -76,14 +78,22 @@ struct channel_oil {
struct channel_counts cc; struct channel_counts cc;
}; };
extern struct list *pim_channel_oil_list;
void pim_oil_init (void);
void pim_oil_terminate (void);
void pim_channel_oil_free(struct channel_oil *c_oil); void pim_channel_oil_free(struct channel_oil *c_oil);
struct channel_oil *pim_channel_oil_add(struct in_addr group_addr, struct channel_oil *pim_channel_oil_add(struct prefix_sg *sg,
struct in_addr source_addr,
int input_vif_index); int input_vif_index);
void pim_channel_oil_del(struct channel_oil *c_oil); void pim_channel_oil_del(struct channel_oil *c_oil);
int pim_channel_add_oif(struct channel_oil *c_oil, int pim_channel_add_oif(struct channel_oil *c_oil,
struct interface *oif, struct interface *oif,
uint32_t proto_mask); uint32_t proto_mask);
int pim_channel_del_oif (struct channel_oil *c_oil,
struct interface *oif,
uint32_t proto_mask);
int pim_channel_oil_empty (struct channel_oil *c_oil);
#endif /* PIM_OIL_H */ #endif /* PIM_OIL_H */

View File

@ -44,6 +44,25 @@ static int on_pim_hello_send(struct thread *t);
static int pim_hello_send(struct interface *ifp, static int pim_hello_send(struct interface *ifp,
uint16_t holdtime); uint16_t holdtime);
static
const char *pim_pim_msgtype2str (enum pim_msg_type type)
{
switch (type)
{
case PIM_MSG_TYPE_HELLO: return "HELLO";
case PIM_MSG_TYPE_REGISTER: return "REGISTER";
case PIM_MSG_TYPE_REG_STOP: return "REGSTOP";
case PIM_MSG_TYPE_JOIN_PRUNE: return "JOINPRUNE";
case PIM_MSG_TYPE_BOOTSTRAP: return "BOOT";
case PIM_MSG_TYPE_ASSERT: return "ASSERT";
case PIM_MSG_TYPE_GRAFT: return "GRAFT";
case PIM_MSG_TYPE_GRAFT_ACK: return "GACK";
case PIM_MSG_TYPE_CANDIDATE: return "CANDIDATE";
}
return "UNKNOWN";
}
static void sock_close(struct interface *ifp) static void sock_close(struct interface *ifp)
{ {
struct pim_interface *pim_ifp = ifp->info; struct pim_interface *pim_ifp = ifp->info;
@ -70,7 +89,10 @@ static void sock_close(struct interface *ifp)
pim_ifp->pim_sock_fd, ifp->name); pim_ifp->pim_sock_fd, ifp->name);
} }
if (close(pim_ifp->pim_sock_fd)) { /*
* If the fd is already deleted no need to do anything here
*/
if (pim_ifp->pim_sock_fd > 0 && close(pim_ifp->pim_sock_fd)) {
zlog_warn("Failure closing PIM socket fd=%d on interface %s: errno=%d: %s", zlog_warn("Failure closing PIM socket fd=%d on interface %s: errno=%d: %s",
pim_ifp->pim_sock_fd, ifp->name, pim_ifp->pim_sock_fd, ifp->name,
errno, safe_strerror(errno)); errno, safe_strerror(errno));
@ -78,11 +100,6 @@ static void sock_close(struct interface *ifp)
pim_ifp->pim_sock_fd = -1; pim_ifp->pim_sock_fd = -1;
pim_ifp->pim_sock_creation = 0; pim_ifp->pim_sock_creation = 0;
zassert(pim_ifp->pim_sock_fd < 0);
zassert(!pim_ifp->t_pim_sock_read);
zassert(!pim_ifp->t_pim_hello_timer);
zassert(!pim_ifp->pim_sock_creation);
} }
void pim_sock_delete(struct interface *ifp, const char *delete_message) void pim_sock_delete(struct interface *ifp, const char *delete_message)
@ -114,67 +131,53 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
{ {
struct ip *ip_hdr; struct ip *ip_hdr;
size_t ip_hlen; /* ip header length in bytes */ size_t ip_hlen; /* ip header length in bytes */
char src_str[100]; char src_str[INET_ADDRSTRLEN];
char dst_str[100]; char dst_str[INET_ADDRSTRLEN];
uint8_t *pim_msg; uint8_t *pim_msg;
int pim_msg_len; int pim_msg_len;
uint8_t pim_version; uint8_t pim_version;
uint8_t pim_type; enum pim_msg_type pim_type;
uint16_t pim_checksum; /* received checksum */ uint16_t pim_checksum; /* received checksum */
uint16_t checksum; /* computed checksum */ uint16_t checksum; /* computed checksum */
struct pim_neighbor *neigh; struct pim_neighbor *neigh;
if (!ifp->info) {
zlog_warn("%s: PIM not enabled on interface %s",
__PRETTY_FUNCTION__, ifp->name);
return -1;
}
if (len < sizeof(*ip_hdr)) { if (len < sizeof(*ip_hdr)) {
zlog_warn("PIM packet size=%zu shorter than minimum=%zu", if (PIM_DEBUG_PIM_PACKETS)
len, sizeof(*ip_hdr)); zlog_debug("PIM packet size=%zu shorter than minimum=%zu",
len, sizeof(*ip_hdr));
return -1; return -1;
} }
ip_hdr = (struct ip *) buf; ip_hdr = (struct ip *) buf;
pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str, sizeof(src_str));
pim_inet4_dump("<dst?>", ip_hdr->ip_dst, dst_str, sizeof(dst_str));
ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */ ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */
if (PIM_DEBUG_PIM_PACKETS) {
zlog_debug("Recv IP packet from %s to %s on %s: size=%zu ip_header_size=%zu ip_proto=%d",
src_str, dst_str, ifp->name, len, ip_hlen, ip_hdr->ip_p);
}
if (ip_hdr->ip_p != PIM_IP_PROTO_PIM) { if (ip_hdr->ip_p != PIM_IP_PROTO_PIM) {
zlog_warn("IP packet protocol=%d is not PIM=%d", if (PIM_DEBUG_PIM_PACKETS)
ip_hdr->ip_p, PIM_IP_PROTO_PIM); zlog_debug("IP packet protocol=%d is not PIM=%d",
ip_hdr->ip_p, PIM_IP_PROTO_PIM);
return -1; return -1;
} }
if (ip_hlen < PIM_IP_HEADER_MIN_LEN) { if (ip_hlen < PIM_IP_HEADER_MIN_LEN) {
zlog_warn("IP packet header size=%zu shorter than minimum=%d", if (PIM_DEBUG_PIM_PACKETS)
ip_hlen, PIM_IP_HEADER_MIN_LEN); zlog_debug("IP packet header size=%zu shorter than minimum=%d",
ip_hlen, PIM_IP_HEADER_MIN_LEN);
return -1; return -1;
} }
if (ip_hlen > PIM_IP_HEADER_MAX_LEN) { if (ip_hlen > PIM_IP_HEADER_MAX_LEN) {
zlog_warn("IP packet header size=%zu greater than maximum=%d", if (PIM_DEBUG_PIM_PACKETS)
ip_hlen, PIM_IP_HEADER_MAX_LEN); zlog_debug("IP packet header size=%zu greater than maximum=%d",
ip_hlen, PIM_IP_HEADER_MAX_LEN);
return -1; return -1;
} }
pim_msg = buf + ip_hlen; pim_msg = buf + ip_hlen;
pim_msg_len = len - ip_hlen; pim_msg_len = len - ip_hlen;
if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_len);
}
if (pim_msg_len < PIM_PIM_MIN_LEN) { if (pim_msg_len < PIM_PIM_MIN_LEN) {
zlog_warn("PIM message size=%d shorter than minimum=%d", if (PIM_DEBUG_PIM_PACKETS)
pim_msg_len, PIM_PIM_MIN_LEN); zlog_debug("PIM message size=%d shorter than minimum=%d",
pim_msg_len, PIM_PIM_MIN_LEN);
return -1; return -1;
} }
@ -182,8 +185,9 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
pim_type = PIM_MSG_HDR_GET_TYPE(pim_msg); pim_type = PIM_MSG_HDR_GET_TYPE(pim_msg);
if (pim_version != PIM_PROTO_VERSION) { if (pim_version != PIM_PROTO_VERSION) {
zlog_warn("Ignoring PIM pkt from %s with unsupported version: %d", if (PIM_DEBUG_PIM_PACKETS)
ifp->name, pim_version); zlog_debug("Ignoring PIM pkt from %s with unsupported version: %d",
ifp->name, pim_version);
return -1; return -1;
} }
@ -195,71 +199,79 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
checksum = in_cksum(pim_msg, pim_msg_len); checksum = in_cksum(pim_msg, pim_msg_len);
if (checksum != pim_checksum) { if (checksum != pim_checksum) {
zlog_warn("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x", if (PIM_DEBUG_PIM_PACKETS)
ifp->name, pim_checksum, checksum); zlog_debug("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
ifp->name, pim_checksum, checksum);
return -1; return -1;
} }
if (PIM_DEBUG_PIM_PACKETS) { if (PIM_DEBUG_PIM_PACKETS) {
zlog_debug("Recv PIM packet from %s to %s on %s: ttl=%d pim_version=%d pim_type=%d pim_msg_size=%d checksum=%x", pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str, sizeof(src_str));
src_str, dst_str, ifp->name, ip_hdr->ip_ttl, pim_inet4_dump("<dst?>", ip_hdr->ip_dst, dst_str, sizeof(dst_str));
pim_version, pim_type, pim_msg_len, checksum); zlog_debug("Recv PIM %s packet from %s to %s on %s: ttl=%d pim_version=%d pim_msg_size=%d checksum=%x",
pim_pim_msgtype2str (pim_type), src_str, dst_str, ifp->name,
ip_hdr->ip_ttl, pim_version, pim_msg_len, checksum);
if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_len);
}
} }
if (pim_type == PIM_MSG_TYPE_REG_STOP || switch (pim_type)
pim_type == PIM_MSG_TYPE_BOOTSTRAP ||
pim_type == PIM_MSG_TYPE_GRAFT ||
pim_type == PIM_MSG_TYPE_GRAFT_ACK ||
pim_type == PIM_MSG_TYPE_CANDIDATE)
{ {
case PIM_MSG_TYPE_HELLO:
return pim_hello_recv (ifp,
ip_hdr->ip_src,
pim_msg + PIM_MSG_HEADER_LEN,
pim_msg_len - PIM_MSG_HEADER_LEN);
break;
case PIM_MSG_TYPE_REGISTER:
return pim_register_recv (ifp,
ip_hdr->ip_dst,
ip_hdr->ip_src,
pim_msg + PIM_MSG_HEADER_LEN,
pim_msg_len - PIM_MSG_HEADER_LEN);
break;
case PIM_MSG_TYPE_REG_STOP:
return pim_register_stop_recv (pim_msg + PIM_MSG_HEADER_LEN,
pim_msg_len - PIM_MSG_HEADER_LEN);
break;
case PIM_MSG_TYPE_JOIN_PRUNE:
neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
if (!neigh) {
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
__FILE__, __PRETTY_FUNCTION__,
pim_type, src_str, ifp->name);
return -1;
}
pim_neighbor_timer_reset(neigh, neigh->holdtime);
return pim_joinprune_recv(ifp, neigh,
ip_hdr->ip_src,
pim_msg + PIM_MSG_HEADER_LEN,
pim_msg_len - PIM_MSG_HEADER_LEN);
break;
case PIM_MSG_TYPE_ASSERT:
neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
if (!neigh) {
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
__FILE__, __PRETTY_FUNCTION__,
pim_type, src_str, ifp->name);
return -1;
}
pim_neighbor_timer_reset(neigh, neigh->holdtime);
return pim_assert_recv(ifp, neigh,
ip_hdr->ip_src,
pim_msg + PIM_MSG_HEADER_LEN,
pim_msg_len - PIM_MSG_HEADER_LEN);
break;
default:
if (PIM_DEBUG_PIM_PACKETS) { if (PIM_DEBUG_PIM_PACKETS) {
zlog_debug("Recv PIM packet type %d which is not currently understood", zlog_debug("Recv PIM packet type %d which is not currently understood",
pim_type); pim_type);
} }
return -1; return -1;
} }
if (pim_type == PIM_MSG_TYPE_HELLO) {
return pim_hello_recv(ifp,
ip_hdr->ip_src,
pim_msg + PIM_MSG_HEADER_LEN,
pim_msg_len - PIM_MSG_HEADER_LEN);
} else if (pim_type == PIM_MSG_TYPE_REGISTER) {
return pim_register_recv(ifp,
ip_hdr->ip_dst,
ip_hdr->ip_src,
pim_msg + PIM_MSG_HEADER_LEN,
pim_msg_len - PIM_MSG_HEADER_LEN);
}
neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
if (!neigh) {
zlog_warn("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
__FILE__, __PRETTY_FUNCTION__,
pim_type, src_str, ifp->name);
return -1;
}
switch (pim_type) {
case PIM_MSG_TYPE_JOIN_PRUNE:
return pim_joinprune_recv(ifp, neigh,
ip_hdr->ip_src,
pim_msg + PIM_MSG_HEADER_LEN,
pim_msg_len - PIM_MSG_HEADER_LEN);
break;
case PIM_MSG_TYPE_ASSERT:
return pim_assert_recv(ifp, neigh,
ip_hdr->ip_src,
pim_msg + PIM_MSG_HEADER_LEN,
pim_msg_len - PIM_MSG_HEADER_LEN);
break;
default:
zlog_warn("%s %s: unsupported PIM message type=%d from %s on %s",
__FILE__, __PRETTY_FUNCTION__,
pim_type, src_str, ifp->name);
break;
}
return -1; return -1;
} }
@ -278,80 +290,73 @@ static int pim_sock_read(struct thread *t)
int len; int len;
ifindex_t ifindex = -1; ifindex_t ifindex = -1;
int result = -1; /* defaults to bad */ int result = -1; /* defaults to bad */
static long long count = 0;
zassert(t); int cont = 1;
ifp = THREAD_ARG(t); ifp = THREAD_ARG(t);
zassert(ifp);
fd = THREAD_FD(t); fd = THREAD_FD(t);
pim_ifp = ifp->info; pim_ifp = ifp->info;
zassert(pim_ifp);
zassert(fd == pim_ifp->pim_sock_fd); while (cont)
{
len = pim_socket_recvfromto(fd, buf, sizeof(buf), len = pim_socket_recvfromto(fd, buf, sizeof(buf),
&from, &fromlen, &from, &fromlen,
&to, &tolen, &to, &tolen,
&ifindex); &ifindex);
if (len < 0) { if (len < 0)
zlog_warn("Failure receiving IP PIM packet on fd=%d: errno=%d: %s", {
fd, errno, safe_strerror(errno)); if (errno == EINTR)
goto done; continue;
} if (errno == EWOULDBLOCK || errno == EAGAIN)
{
if (PIM_DEBUG_PIM_PACKETS) { cont = 0;
char from_str[100]; break;
char to_str[100]; }
if (PIM_DEBUG_PIM_PACKETS)
if (!inet_ntop(AF_INET, &from.sin_addr, from_str, sizeof(from_str))) zlog_debug ("Received errno: %d %s", errno, safe_strerror (errno));
sprintf(from_str, "<from?>"); goto done;
if (!inet_ntop(AF_INET, &to.sin_addr, to_str, sizeof(to_str))) }
sprintf(to_str, "<to?>");
zlog_debug("Recv IP PIM pkt size=%d from %s to %s on fd=%d on ifindex=%d (sock_ifindex=%d)",
len, from_str, to_str, fd, ifindex, ifp->ifindex);
}
if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
pim_pkt_dump(__PRETTY_FUNCTION__, buf, len);
}
#ifdef PIM_CHECK_RECV_IFINDEX_SANITY #ifdef PIM_CHECK_RECV_IFINDEX_SANITY
/* ifindex sanity check */ /* ifindex sanity check */
if (ifindex != (int) ifp->ifindex) { if (ifindex != (int) ifp->ifindex) {
char from_str[100]; char from_str[INET_ADDRSTRLEN];
char to_str[100]; char to_str[INET_ADDRSTRLEN];
struct interface *recv_ifp; struct interface *recv_ifp;
if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str))) if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str)))
sprintf(from_str, "<from?>"); sprintf(from_str, "<from?>");
if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str))) if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str)))
sprintf(to_str, "<to?>"); sprintf(to_str, "<to?>");
recv_ifp = if_lookup_by_index(ifindex); recv_ifp = if_lookup_by_index(ifindex);
if (recv_ifp) { if (recv_ifp) {
zassert(ifindex == (int) recv_ifp->ifindex); zassert(ifindex == (int) recv_ifp->ifindex);
} }
#ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH #ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH
zlog_warn("Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)", zlog_warn("Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)",
from_str, to_str, fd, from_str, to_str, fd,
ifindex, recv_ifp ? recv_ifp->name : "<if-notfound>", ifindex, recv_ifp ? recv_ifp->name : "<if-notfound>",
ifp->ifindex, ifp->name); ifp->ifindex, ifp->name);
#endif #endif
goto done; goto done;
} }
#endif #endif
int fail = pim_pim_packet(ifp, buf, len); int fail = pim_pim_packet(ifp, buf, len);
if (fail) { if (fail) {
if (PIM_DEBUG_PIM_PACKETS) if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("%s: pim_pim_packet() return=%d", zlog_debug("%s: pim_pim_packet() return=%d",
__PRETTY_FUNCTION__, fail); __PRETTY_FUNCTION__, fail);
goto done; goto done;
} }
count++;
if (count % qpim_packet_process == 0)
cont = 0;
}
result = 0; /* good */ result = 0; /* good */
@ -378,7 +383,7 @@ static void pim_sock_read_on(struct interface *ifp)
zlog_debug("Scheduling READ event on PIM socket fd=%d", zlog_debug("Scheduling READ event on PIM socket fd=%d",
pim_ifp->pim_sock_fd); pim_ifp->pim_sock_fd);
} }
pim_ifp->t_pim_sock_read = 0; pim_ifp->t_pim_sock_read = NULL;
zassert(!pim_ifp->t_pim_sock_read); zassert(!pim_ifp->t_pim_sock_read);
THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp, THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp,
pim_ifp->pim_sock_fd); pim_ifp->pim_sock_fd);
@ -431,9 +436,9 @@ void pim_sock_reset(struct interface *ifp)
pim_ifp->pim_sock_fd = -1; pim_ifp->pim_sock_fd = -1;
pim_ifp->pim_sock_creation = 0; pim_ifp->pim_sock_creation = 0;
pim_ifp->t_pim_sock_read = 0; pim_ifp->t_pim_sock_read = NULL;
pim_ifp->t_pim_hello_timer = 0; pim_ifp->t_pim_hello_timer = NULL;
pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD; pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD;
pim_ifp->pim_default_holdtime = -1; /* unset: means 3.5 * pim_hello_period */ pim_ifp->pim_default_holdtime = -1; /* unset: means 3.5 * pim_hello_period */
pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY; pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY;
@ -462,18 +467,91 @@ void pim_sock_reset(struct interface *ifp)
pim_ifstat_reset(ifp); pim_ifstat_reset(ifp);
} }
int pim_msg_send(int fd, static uint16_t ip_id = 0;
struct in_addr dst,
uint8_t *pim_msg,
int pim_msg_size, static int
const char *ifname) pim_msg_send_frame (int fd, char *buf, size_t len,
struct sockaddr *dst, size_t salen)
{
struct ip *ip = (struct ip *)buf;
while (sendto (fd, buf, len, MSG_DONTWAIT, dst, salen) < 0)
{
char dst_str[INET_ADDRSTRLEN];
switch (errno)
{
case EMSGSIZE:
{
size_t hdrsize = sizeof (struct ip);
size_t newlen1 = ((len - hdrsize) / 2 ) & 0xFFF8;
size_t sendlen = newlen1 + hdrsize;
size_t offset = ntohs (ip->ip_off);
ip->ip_len = htons (sendlen);
ip->ip_off = htons (offset | IP_MF);
if (pim_msg_send_frame (fd, buf, sendlen, dst, salen) == 0)
{
struct ip *ip2 = (struct ip *)(buf + newlen1);
size_t newlen2 = len - sendlen;
sendlen = newlen2 + hdrsize;
memcpy (ip2, ip, hdrsize);
ip2->ip_len = htons (sendlen);
ip2->ip_off = htons (offset + (newlen1 >> 3));
return pim_msg_send_frame (fd, (char *)ip2, sendlen, dst, salen);
}
}
return -1;
break;
default:
if (PIM_DEBUG_PIM_PACKETS)
{
pim_inet4_dump ("<dst?>", ip->ip_dst, dst_str, sizeof (dst_str));
zlog_warn ("%s: sendto() failure to %s: fd=%d msg_size=%zd: errno=%d: %s",
__PRETTY_FUNCTION__,
dst_str, fd, len,
errno, safe_strerror(errno));
}
return -1;
break;
}
}
return 0;
}
int
pim_msg_send(int fd, struct in_addr src,
struct in_addr dst, uint8_t *pim_msg,
int pim_msg_size, const char *ifname)
{ {
ssize_t sent;
struct sockaddr_in to; struct sockaddr_in to;
socklen_t tolen; socklen_t tolen;
unsigned char buffer[10000];
unsigned char *msg_start;
struct ip *ip;
memset (buffer, 0, 10000);
int sendlen = sizeof (struct ip) + pim_msg_size;
msg_start = buffer + sizeof (struct ip);
memcpy (msg_start, pim_msg, pim_msg_size);
ip = (struct ip *)buffer;
ip->ip_id = htons (++ip_id);
ip->ip_hl = 5;
ip->ip_v = 4;
ip->ip_p = PIM_IP_PROTO_PIM;
ip->ip_src = src;
ip->ip_dst = dst;
ip->ip_ttl = MAXTTL;
ip->ip_len = htons (sendlen);
if (PIM_DEBUG_PIM_PACKETS) { if (PIM_DEBUG_PIM_PACKETS) {
char dst_str[100]; char dst_str[INET_ADDRSTRLEN];
pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str)); pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x", zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -490,27 +568,8 @@ int pim_msg_send(int fd,
pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size); pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
} }
sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT, pim_msg_send_frame (fd, (char *)buffer, sendlen,
(struct sockaddr *)&to, tolen); (struct sockaddr *)&to, tolen);
if (sent != (ssize_t) pim_msg_size) {
int e = errno;
char dst_str[100];
pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
if (sent < 0) {
zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s",
__PRETTY_FUNCTION__,
dst_str, ifname, fd, pim_msg_size,
e, safe_strerror(e));
}
else {
zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd",
__PRETTY_FUNCTION__,
dst_str, ifname, fd,
pim_msg_size, sent);
}
return -1;
}
return 0; return 0;
} }
@ -525,7 +584,7 @@ static int hello_send(struct interface *ifp,
pim_ifp = ifp->info; pim_ifp = ifp->info;
if (PIM_DEBUG_PIM_HELLO) { if (PIM_DEBUG_PIM_HELLO) {
char dst_str[100]; char dst_str[INET_ADDRSTRLEN];
pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr, dst_str, sizeof(dst_str)); pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr, dst_str, sizeof(dst_str));
zlog_debug("%s: to %s on %s: holdt=%u prop_d=%u overr_i=%u dis_join_supp=%d dr_prio=%u gen_id=%08x addrs=%d", zlog_debug("%s: to %s on %s: holdt=%u prop_d=%u overr_i=%u dis_join_supp=%d dr_prio=%u gen_id=%08x addrs=%d",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -560,6 +619,7 @@ static int hello_send(struct interface *ifp,
PIM_MSG_TYPE_HELLO); PIM_MSG_TYPE_HELLO);
if (pim_msg_send(pim_ifp->pim_sock_fd, if (pim_msg_send(pim_ifp->pim_sock_fd,
pim_ifp->primary_address,
qpim_all_pim_routers_addr, qpim_all_pim_routers_addr,
pim_msg, pim_msg,
pim_msg_size, pim_msg_size,
@ -627,16 +687,14 @@ static int on_pim_hello_send(struct thread *t)
struct pim_interface *pim_ifp; struct pim_interface *pim_ifp;
struct interface *ifp; struct interface *ifp;
zassert(t);
ifp = THREAD_ARG(t); ifp = THREAD_ARG(t);
zassert(ifp);
pim_ifp = ifp->info; pim_ifp = ifp->info;
/* /*
* Schedule next hello * Schedule next hello
*/ */
pim_ifp->t_pim_hello_timer = 0; pim_ifp->t_pim_hello_timer = NULL;
hello_resched(ifp); hello_resched(ifp);
/* /*
@ -692,7 +750,20 @@ void pim_hello_restart_triggered(struct interface *ifp)
pim_ifp = ifp->info; pim_ifp = ifp->info;
zassert(pim_ifp); zassert(pim_ifp);
triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay; /*
* There exists situations where we have the a RPF out this
* interface, but we haven't formed a neighbor yet. This
* happens especially during interface flaps. While
* we would like to handle this more gracefully in other
* parts of the code. In order to get us up and running
* let's just send the hello immediate'ish
* This should be revisited when we get nexthop tracking
* in and when we have a better handle on safely
* handling the rpf information for upstreams that
* we cannot legally reach yet.
*/
triggered_hello_delay_msec = 1;
//triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay;
if (pim_ifp->t_pim_hello_timer) { if (pim_ifp->t_pim_hello_timer) {
long remain_msec = pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer); long remain_msec = pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
@ -703,11 +774,11 @@ void pim_hello_restart_triggered(struct interface *ifp)
} }
THREAD_OFF(pim_ifp->t_pim_hello_timer); THREAD_OFF(pim_ifp->t_pim_hello_timer);
pim_ifp->t_pim_hello_timer = 0; pim_ifp->t_pim_hello_timer = NULL;
} }
zassert(!pim_ifp->t_pim_hello_timer);
random_msec = random() % (triggered_hello_delay_msec + 1); random_msec = triggered_hello_delay_msec;
//random_msec = random() % (triggered_hello_delay_msec + 1);
if (PIM_DEBUG_PIM_HELLO) { if (PIM_DEBUG_PIM_HELLO) {
zlog_debug("Scheduling %d msec triggered hello on interface %s", zlog_debug("Scheduling %d msec triggered hello on interface %s",
@ -729,8 +800,9 @@ int pim_sock_add(struct interface *ifp)
zassert(pim_ifp); zassert(pim_ifp);
if (pim_ifp->pim_sock_fd >= 0) { if (pim_ifp->pim_sock_fd >= 0) {
zlog_warn("Can't recreate existing PIM socket fd=%d for interface %s", if (PIM_DEBUG_PIM_PACKETS)
pim_ifp->pim_sock_fd, ifp->name); zlog_debug("Can't recreate existing PIM socket fd=%d for interface %s",
pim_ifp->pim_sock_fd, ifp->name);
return -1; return -1;
} }
@ -738,12 +810,15 @@ int pim_sock_add(struct interface *ifp)
pim_ifp->pim_sock_fd = pim_sock_open(ifaddr, ifp->ifindex); pim_ifp->pim_sock_fd = pim_sock_open(ifaddr, ifp->ifindex);
if (pim_ifp->pim_sock_fd < 0) { if (pim_ifp->pim_sock_fd < 0) {
zlog_warn("Could not open PIM socket on interface %s", if (PIM_DEBUG_PIM_PACKETS)
ifp->name); zlog_debug("Could not open PIM socket on interface %s",
ifp->name);
return -2; return -2;
} }
pim_ifp->t_pim_sock_read = 0; pim_socket_ip_hdr (pim_ifp->pim_sock_fd);
pim_ifp->t_pim_sock_read = NULL;
pim_ifp->pim_sock_creation = pim_time_monotonic_sec(); pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
/* /*

View File

@ -28,8 +28,6 @@
#define PIM_PIM_BUFSIZE_READ (20000) #define PIM_PIM_BUFSIZE_READ (20000)
#define PIM_PIM_BUFSIZE_WRITE (20000) #define PIM_PIM_BUFSIZE_WRITE (20000)
#define PIM_NEXTHOP_IFINDEX_TAB_SIZE (20)
#define PIM_DEFAULT_HELLO_PERIOD (30) /* seconds, RFC 4601: 4.11 */ #define PIM_DEFAULT_HELLO_PERIOD (30) /* seconds, RFC 4601: 4.11 */
#define PIM_DEFAULT_TRIGGERED_HELLO_DELAY (5) /* seconds, RFC 4601: 4.11 */ #define PIM_DEFAULT_TRIGGERED_HELLO_DELAY (5) /* seconds, RFC 4601: 4.11 */
#define PIM_DEFAULT_DR_PRIORITY (1) /* RFC 4601: 4.3.1 */ #define PIM_DEFAULT_DR_PRIORITY (1) /* RFC 4601: 4.3.1 */
@ -38,15 +36,17 @@
#define PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION (0) /* boolean */ #define PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION (0) /* boolean */
#define PIM_DEFAULT_T_PERIODIC (60) /* RFC 4601: 4.11. Timer Values */ #define PIM_DEFAULT_T_PERIODIC (60) /* RFC 4601: 4.11. Timer Values */
#define PIM_MSG_TYPE_HELLO (0) enum pim_msg_type {
#define PIM_MSG_TYPE_REGISTER (1) PIM_MSG_TYPE_HELLO = 0,
#define PIM_MSG_TYPE_REG_STOP (2) PIM_MSG_TYPE_REGISTER,
#define PIM_MSG_TYPE_JOIN_PRUNE (3) PIM_MSG_TYPE_REG_STOP,
#define PIM_MSG_TYPE_BOOTSTRAP (4) PIM_MSG_TYPE_JOIN_PRUNE,
#define PIM_MSG_TYPE_ASSERT (5) PIM_MSG_TYPE_BOOTSTRAP,
#define PIM_MSG_TYPE_GRAFT (6) PIM_MSG_TYPE_ASSERT,
#define PIM_MSG_TYPE_GRAFT_ACK (7) PIM_MSG_TYPE_GRAFT,
#define PIM_MSG_TYPE_CANDIDATE (8) PIM_MSG_TYPE_GRAFT_ACK,
PIM_MSG_TYPE_CANDIDATE
};
#define PIM_MSG_HDR_OFFSET_VERSION(pim_msg) (pim_msg) #define PIM_MSG_HDR_OFFSET_VERSION(pim_msg) (pim_msg)
#define PIM_MSG_HDR_OFFSET_TYPE(pim_msg) (pim_msg) #define PIM_MSG_HDR_OFFSET_TYPE(pim_msg) (pim_msg)
@ -67,6 +67,7 @@ void pim_hello_restart_triggered(struct interface *ifp);
int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len); int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len);
int pim_msg_send(int fd, int pim_msg_send(int fd,
struct in_addr src,
struct in_addr dst, struct in_addr dst,
uint8_t *pim_msg, uint8_t *pim_msg,
int pim_msg_size, int pim_msg_size,

View File

@ -24,6 +24,9 @@
#include "log.h" #include "log.h"
#include "if.h" #include "if.h"
#include "thread.h" #include "thread.h"
#include "prefix.h"
#include "vty.h"
#include "plist.h"
#include "pimd.h" #include "pimd.h"
#include "pim_mroute.h" #include "pim_mroute.h"
@ -39,65 +42,150 @@
#include "pim_oil.h" #include "pim_oil.h"
#include "pim_zebra.h" #include "pim_zebra.h"
#include "pim_join.h" #include "pim_join.h"
#include "pim_util.h"
struct thread *send_test_packet_timer = NULL; struct thread *send_test_packet_timer = NULL;
/* void
* This seems stupidly expensive. A list lookup. Why is this pim_register_stop_send (struct interface *ifp, struct prefix_sg *sg,
* not a hash? struct in_addr src, struct in_addr originator)
*/
static int
pim_check_is_my_ip_address (struct in_addr dest_addr)
{ {
/* struct pim_interface *pinfo;
* See if we can short-cut some? unsigned char buffer[10000];
* This might not make sense if we ever leave a static RP unsigned int b1length = 0;
* type of configuration. unsigned int length;
* Note - Premature optimization might bite our patooeys' here. uint8_t *b1;
*/ struct prefix p;
if (I_am_RP(dest_addr) && (dest_addr.s_addr == qpim_rp.rpf_addr.s_addr))
return 1;
if (if_lookup_exact_address (&dest_addr, AF_INET)) if (PIM_DEBUG_PIM_REG)
return 1; {
zlog_debug ("Sending Register stop for %s to %s on %s",
pim_str_sg_dump (sg), inet_ntoa(originator), ifp->name);
}
memset (buffer, 0, 10000);
b1 = (uint8_t *)buffer + PIM_MSG_REGISTER_STOP_LEN;
length = pim_encode_addr_group (b1, AFI_IP, 0, 0, sg->grp);
b1length += length;
b1 += length;
p.family = AF_INET;
p.u.prefix4 = sg->src;
p.prefixlen = 32;
length = pim_encode_addr_ucast (b1, &p);
b1length += length;
pim_msg_build_header (buffer, b1length + PIM_MSG_REGISTER_STOP_LEN, PIM_MSG_TYPE_REG_STOP);
pinfo = (struct pim_interface *)ifp->info;
if (!pinfo)
{
if (PIM_DEBUG_PIM_TRACE)
zlog_debug ("%s: No pinfo!\n", __PRETTY_FUNCTION__);
return;
}
if (pim_msg_send (pinfo->pim_sock_fd, src, originator,
buffer, b1length + PIM_MSG_REGISTER_STOP_LEN,
ifp->name))
{
if (PIM_DEBUG_PIM_TRACE)
{
zlog_debug ("%s: could not send PIM register stop message on interface %s",
__PRETTY_FUNCTION__, ifp->name);
}
}
}
int
pim_register_stop_recv (uint8_t *buf, int buf_size)
{
struct pim_upstream *upstream = NULL;
struct prefix source;
struct prefix_sg sg;
int l;
memset (&sg, 0, sizeof (struct prefix_sg));
l = pim_parse_addr_group (&sg, buf, buf_size);
buf += l;
buf_size -= l;
pim_parse_addr_ucast (&source, buf, buf_size);
sg.src = source.u.prefix4;
upstream = pim_upstream_find (&sg);
if (!upstream)
{
return 0;
}
if (PIM_DEBUG_PIM_REG)
zlog_debug ("Received Register stop for %s",
upstream->sg_str);
switch (upstream->join_state)
{
case PIM_UPSTREAM_NOTJOINED:
case PIM_UPSTREAM_PRUNE:
return 0;
break;
case PIM_UPSTREAM_JOINED:
upstream->join_state = PIM_UPSTREAM_PRUNE;
pim_channel_del_oif (upstream->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
pim_upstream_start_register_stop_timer (upstream, 0);
case PIM_UPSTREAM_JOIN_PENDING:
upstream->join_state = PIM_UPSTREAM_PRUNE;
pim_upstream_start_register_stop_timer (upstream, 0);
return 0;
break;
}
return 0; return 0;
} }
static void
pim_register_stop_send (struct in_addr src)
{
return;
}
void void
pim_register_send (const struct ip *ip_hdr, struct pim_rpf *rpg) pim_register_send (const uint8_t *buf, int buf_size, struct in_addr src, struct pim_rpf *rpg, int null_register, struct pim_upstream *up)
{ {
unsigned char buffer[3000]; unsigned char buffer[10000];
unsigned char *b1; unsigned char *b1;
struct pim_interface *pinfo; struct pim_interface *pinfo;
struct interface *ifp; struct interface *ifp;
uint32_t plen;
if (PIM_DEBUG_PIM_REG)
{
char rp_str[INET_ADDRSTRLEN];
strcpy (rp_str, inet_ntoa (rpg->rpf_addr.u.prefix4));
zlog_debug ("Sending %s %sRegister Packet to %s",
up->sg_str, null_register ? "NULL " : "", rp_str);
}
ifp = rpg->source_nexthop.interface; ifp = rpg->source_nexthop.interface;
if (!ifp)
{
if (PIM_DEBUG_PIM_REG)
zlog_debug ("%s: No interface to transmit register on", __PRETTY_FUNCTION__);
return;
}
pinfo = (struct pim_interface *)ifp->info; pinfo = (struct pim_interface *)ifp->info;
if (!pinfo) { if (!pinfo) {
zlog_debug("%s: No pinfo!\n", __PRETTY_FUNCTION__); if (PIM_DEBUG_PIM_REG)
zlog_debug("%s: Interface: %s not configured for pim to trasmit on!\n", __PRETTY_FUNCTION__, ifp->name);
return; return;
} }
memset(buffer, 0, 3000); memset(buffer, 0, 10000);
b1 = buffer + PIM_MSG_HEADER_LEN;
*b1 |= null_register << 6;
b1 = buffer + PIM_MSG_REGISTER_LEN; b1 = buffer + PIM_MSG_REGISTER_LEN;
plen = ntohs(ip_hdr->ip_len); memcpy(b1, (const unsigned char *)buf, buf_size);
memcpy(b1, (const unsigned char *)ip_hdr, plen);
pim_msg_build_header(buffer, plen + PIM_MSG_REGISTER_LEN, PIM_MSG_TYPE_REGISTER); pim_msg_build_header(buffer, buf_size + PIM_MSG_REGISTER_LEN, PIM_MSG_TYPE_REGISTER);
if (pim_msg_send(pinfo->pim_sock_fd, if (pim_msg_send(pinfo->pim_sock_fd,
rpg->rpf_addr, src,
rpg->rpf_addr.u.prefix4,
buffer, buffer,
plen + PIM_MSG_REGISTER_LEN, buf_size + PIM_MSG_REGISTER_LEN,
ifp->name)) { ifp->name)) {
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_TRACE) {
zlog_debug("%s: could not send PIM register message on interface %s", zlog_debug("%s: could not send PIM register message on interface %s",
@ -159,15 +247,16 @@ pim_register_recv (struct interface *ifp,
{ {
int sentRegisterStop = 0; int sentRegisterStop = 0;
struct ip *ip_hdr; struct ip *ip_hdr;
//size_t hlen; struct prefix_sg sg;
struct in_addr group = { .s_addr = 0 };
struct in_addr source = { .s_addr = 0 };
//uint8_t *msg;
uint32_t *bits; uint32_t *bits;
int i_am_rp = 0;
if (!pim_check_is_my_ip_address (dest_addr)) { #define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4
if (PIM_DEBUG_PIM_PACKETS) { ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN);
char dest[100];
if (!pim_rp_check_is_my_ip_address (ip_hdr->ip_dst, dest_addr)) {
if (PIM_DEBUG_PIM_REG) {
char dest[INET_ADDRSTRLEN];
pim_inet4_dump ("<dst?>", dest_addr, dest, sizeof(dest)); pim_inet4_dump ("<dst?>", dest_addr, dest, sizeof(dest));
zlog_debug ("%s: Received Register message for %s that I do not own", __func__, zlog_debug ("%s: Received Register message for %s that I do not own", __func__,
@ -176,7 +265,6 @@ pim_register_recv (struct interface *ifp,
return 0; return 0;
} }
#define inherited_olist(S,G) NULL
/* /*
* Please note this is not drawn to get the correct bit/data size * Please note this is not drawn to get the correct bit/data size
* *
@ -203,25 +291,33 @@ pim_register_recv (struct interface *ifp,
* Line above. So we need to add 4 bytes to get to the * Line above. So we need to add 4 bytes to get to the
* start of the actual Encapsulated data. * start of the actual Encapsulated data.
*/ */
#define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4 memset (&sg, 0, sizeof (struct prefix_sg));
ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN); sg.src = ip_hdr->ip_src;
//hlen = (ip_hdr->ip_hl << 2) | PIM_MSG_REGISTER_LEN; sg.grp = ip_hdr->ip_dst;
//msg = (uint8_t *)tlv_buf + hlen;
source = ip_hdr->ip_src;
group = ip_hdr->ip_dst;
if (I_am_RP (group) && (dest_addr.s_addr == ((RP (group))->rpf_addr.s_addr))) { i_am_rp = I_am_RP (sg.grp);
if (PIM_DEBUG_PIM_REG)
{
char src_str[INET_ADDRSTRLEN];
pim_inet4_dump ("<src?>", src_addr, src_str, sizeof (src_str));
zlog_debug ("Received Register message(%s) from %s on %s, rp: %d",
pim_str_sg_dump (&sg), src_str, ifp->name, i_am_rp);
}
if (i_am_rp && (dest_addr.s_addr == ((RP (sg.grp))->rpf_addr.u.prefix4.s_addr))) {
sentRegisterStop = 0; sentRegisterStop = 0;
if (*bits & PIM_REGISTER_BORDER_BIT) { if (*bits & PIM_REGISTER_BORDER_BIT) {
struct in_addr pimbr = pim_br_get_pmbr (source, group); struct in_addr pimbr = pim_br_get_pmbr (&sg);
if (PIM_DEBUG_PIM_PACKETS) if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("%s: Received Register message with Border bit set", __func__); zlog_debug("%s: Received Register message with Border bit set", __func__);
if (pimbr.s_addr == pim_br_unknown.s_addr) if (pimbr.s_addr == pim_br_unknown.s_addr)
pim_br_set_pmbr(source, group, src_addr); pim_br_set_pmbr(&sg, src_addr);
else if (src_addr.s_addr != pimbr.s_addr) { else if (src_addr.s_addr != pimbr.s_addr) {
pim_register_stop_send(src_addr); pim_register_stop_send (ifp, &sg, dest_addr, src_addr);
if (PIM_DEBUG_PIM_PACKETS) if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("%s: Sending register-Stop to %s and dropping mr. packet", zlog_debug("%s: Sending register-Stop to %s and dropping mr. packet",
__func__, "Sender"); __func__, "Sender");
@ -230,83 +326,81 @@ pim_register_recv (struct interface *ifp,
} }
} }
struct pim_upstream *upstream = pim_upstream_find (source, group); struct pim_upstream *upstream = pim_upstream_find (&sg);
/* /*
* If we don't have a place to send ignore the packet * If we don't have a place to send ignore the packet
*/ */
if (!upstream) if (!upstream)
return 1; {
upstream = pim_upstream_add (&sg, ifp,
PIM_UPSTREAM_FLAG_MASK_SRC_STREAM,
__PRETTY_FUNCTION__);
if (!upstream)
{
zlog_warn ("Failure to create upstream state");
return 1;
}
PIM_UPSTREAM_FLAG_SET_SRC_STREAM(upstream->flags);
upstream->upstream_register = src_addr;
pim_rp_set_upstream_addr (&upstream->upstream_addr, sg.src, sg.grp);
if (pim_nexthop_lookup (&upstream->rpf.source_nexthop,
upstream->upstream_addr, 1) != 0)
{
if (PIM_DEBUG_PIM_REG)
{
zlog_debug ("Received Register(%s), for which I have no path back", upstream->sg_str);
}
PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(upstream->flags);
pim_upstream_del (upstream, __PRETTY_FUNCTION__);
return 1;
}
upstream->sg.src = sg.src;
upstream->rpf.rpf_addr = upstream->rpf.source_nexthop.mrib_nexthop_addr;
upstream->join_state = PIM_UPSTREAM_PRUNE;
}
if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) || if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) ||
((SwitchToSptDesired(source, group)) && ((SwitchToSptDesired(&sg)) &&
(inherited_olist(source, group) == NULL))) { pim_upstream_inherited_olist (upstream) == 0)) {
pim_register_stop_send(src_addr); //pim_scan_individual_oil (upstream->channel_oil);
pim_register_stop_send (ifp, &sg, dest_addr, src_addr);
sentRegisterStop = 1; sentRegisterStop = 1;
} else {
if (PIM_DEBUG_PIM_REG)
zlog_debug ("(%s) sptbit: %d", upstream->sg_str, upstream->sptbit);
} }
if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) || if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) ||
(SwitchToSptDesired(source, group))) { (SwitchToSptDesired(&sg))) {
if (sentRegisterStop) { if (sentRegisterStop) {
pim_upstream_keep_alive_timer_start (upstream, PIM_RP_KEEPALIVE_PERIOD); pim_upstream_keep_alive_timer_start (upstream, qpim_rp_keep_alive_time);
} else { } else {
pim_upstream_keep_alive_timer_start (upstream, PIM_KEEPALIVE_PERIOD); pim_upstream_keep_alive_timer_start (upstream, qpim_keep_alive_time);
} }
} }
if (!(upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) && if (!(upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) &&
!(*bits & PIM_REGISTER_NR_BIT)) !(*bits & PIM_REGISTER_NR_BIT))
{ {
pim_rp_set_upstream_addr (&upstream->upstream_addr, source);
pim_nexthop_lookup (&upstream->rpf.source_nexthop,
upstream->upstream_addr, NULL);
upstream->rpf.source_nexthop.interface = ifp;
upstream->source_addr.s_addr = source.s_addr;
upstream->rpf.rpf_addr.s_addr = source.s_addr;
upstream->channel_oil->oil.mfcc_origin = source;
pim_scan_individual_oil (upstream->channel_oil);
pim_joinprune_send(upstream->rpf.source_nexthop.interface,
upstream->rpf.source_nexthop.mrib_nexthop_addr,
upstream->source_addr,
upstream->group_addr,
1);
//decapsulate and forward the iner packet to //decapsulate and forward the iner packet to
//inherited_olist(S,G,rpt) //inherited_olist(S,G,rpt)
// This is taken care of by the kernel for us
} }
pim_upstream_msdp_reg_timer_start(upstream);
} else { } else {
pim_register_stop_send(src_addr); if (PIM_DEBUG_PIM_REG)
{
if (!i_am_rp)
zlog_debug ("Received Register packet for %s, Rejecting packet because I am not the RP configured for group",
pim_str_sg_dump (&sg));
else
zlog_debug ("Received Register packet for %s, Rejecting packet because the dst ip address is not the actual RP",
pim_str_sg_dump (&sg));
}
pim_register_stop_send (ifp, &sg, dest_addr, src_addr);
} }
return 1; return 1;
} }
static int
pim_register_send_test_packet (struct thread *t)
{
uint8_t *packet;
packet = THREAD_ARG(t);
*packet = 4;
return 1;
}
/*
* pim_register_send_test_packet
*
* Send a test packet to the RP from source, in group and pps packets per second
*/
void
pim_register_send_test_packet_start (struct in_addr source,
struct in_addr group,
uint32_t pps)
{
uint8_t *packet = NULL;
THREAD_TIMER_MSEC_ON(master, send_test_packet_timer,
pim_register_send_test_packet, packet, 1000/pps);
return;
}

View File

@ -31,15 +31,14 @@
#define PIM_MSG_REGISTER_LEN (8) #define PIM_MSG_REGISTER_LEN (8)
#define PIM_MSG_REGISTER_STOP_LEN (4) #define PIM_MSG_REGISTER_STOP_LEN (4)
void pim_register_send_test_packet_start (struct in_addr source, int pim_register_stop_recv (uint8_t *buf, int buf_size);
struct in_addr group,
uint32_t pps);
int pim_register_recv (struct interface *ifp, int pim_register_recv (struct interface *ifp,
struct in_addr dest_addr, struct in_addr dest_addr,
struct in_addr src_addr, struct in_addr src_addr,
uint8_t *tlv_buf, int tlv_buf_size); uint8_t *tlv_buf, int tlv_buf_size);
void pim_register_send (const struct ip *msg, struct pim_rpf *rpg); void pim_register_send (const uint8_t *buf, int buf_size, struct in_addr src, struct pim_rpf *rpg, int null_register, struct pim_upstream *up);
void pim_register_stop_send (struct interface *ifp, struct prefix_sg *sg, struct in_addr src, struct in_addr originator);
#endif #endif

View File

@ -20,48 +20,597 @@
*/ */
#include <zebra.h> #include <zebra.h>
#include "lib/json.h"
#include "log.h" #include "log.h"
#include "network.h" #include "network.h"
#include "if.h" #include "if.h"
#include "linklist.h"
#include "prefix.h"
#include "memory.h"
#include "vty.h"
#include "vrf.h"
#include "plist.h"
#include "pimd.h" #include "pimd.h"
#include "pim_vty.h"
#include "pim_str.h" #include "pim_str.h"
#include "pim_iface.h"
#include "pim_rp.h" #include "pim_rp.h"
#include "pim_str.h" #include "pim_str.h"
#include "pim_rpf.h" #include "pim_rpf.h"
#include "pim_sock.h"
#include "pim_memory.h"
#include "pim_iface.h"
#include "pim_msdp.h"
static int i_am_rp = 0; struct rp_info
/*
* Checks to see if we should elect ourself the actual RP
*/
void
pim_rp_check_rp (struct in_addr old, struct in_addr new)
{ {
if (PIM_DEBUG_ZEBRA) { struct prefix group;
char sold[100]; struct pim_rpf rp;
char snew[100]; int i_am_rp;
char rp[100]; char *plist;
pim_inet4_dump("<rp?>", qpim_rp.rpf_addr, rp, sizeof(rp)); };
pim_inet4_dump("<old?>", old, sold, sizeof(sold));
pim_inet4_dump("<new?>", new, snew, sizeof(snew));
zlog_debug("%s: %s for old %s new %s", __func__, rp, sold, snew );
}
if (qpim_rp.rpf_addr.s_addr == INADDR_NONE) static struct list *qpim_rp_list = NULL;
static struct rp_info *tail = NULL;
static void
pim_rp_info_free (struct rp_info *rp_info)
{
XFREE (MTYPE_PIM_RP, rp_info);
}
static int
pim_rp_list_cmp (void *v1, void *v2)
{
struct rp_info *rp1 = (struct rp_info *)v1;
struct rp_info *rp2 = (struct rp_info *)v2;
if (rp1 == rp2)
return 0;
if (!rp1 && rp2)
return -1;
if (rp1 && !rp2)
return 1;
/*
* Sort by RP IP address
*/
if (rp1->rp.rpf_addr.u.prefix4.s_addr < rp2->rp.rpf_addr.u.prefix4.s_addr)
return -1;
if (rp1->rp.rpf_addr.u.prefix4.s_addr > rp2->rp.rpf_addr.u.prefix4.s_addr)
return 1;
/*
* Sort by group IP address
*/
if (rp1->group.u.prefix4.s_addr < rp2->group.u.prefix4.s_addr)
return -1;
if (rp1->group.u.prefix4.s_addr > rp2->group.u.prefix4.s_addr)
return 1;
if (rp1 == tail)
return 1;
return -1;
}
void
pim_rp_init (void)
{
struct rp_info *rp_info;
qpim_rp_list = list_new ();
qpim_rp_list->del = (void (*)(void *))pim_rp_info_free;
qpim_rp_list->cmp = pim_rp_list_cmp;
rp_info = XCALLOC (MTYPE_PIM_RP, sizeof (*rp_info));
if (!rp_info)
return; return;
if (new.s_addr == qpim_rp.rpf_addr.s_addr) str2prefix ("224.0.0.0/4", &rp_info->group);
rp_info->group.family = AF_INET;
rp_info->rp.rpf_addr.family = AF_INET;
rp_info->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE;
tail = rp_info;
listnode_add (qpim_rp_list, rp_info);
}
void
pim_rp_free (void)
{
if (qpim_rp_list)
list_free (qpim_rp_list);
}
/*
* Given an RP's prefix-list, return the RP's rp_info for that prefix-list
*/
static struct rp_info *
pim_rp_find_prefix_list (struct in_addr rp, const char *plist)
{
struct listnode *node;
struct rp_info *rp_info;
for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
{ {
i_am_rp = 1; if (rp.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr &&
return; rp_info->plist && strcmp(rp_info->plist, plist) == 0)
{
return rp_info;
}
} }
if (old.s_addr == qpim_rp.rpf_addr.s_addr) return NULL;
}
/*
* Return true if plist is used by any rp_info
*/
static int
pim_rp_prefix_list_used (const char *plist)
{
struct listnode *node;
struct rp_info *rp_info;
for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
{ {
i_am_rp = 0; if (rp_info->plist && strcmp(rp_info->plist, plist) == 0)
return; {
return 1;
}
} }
return 0;
}
/*
* Given an RP's address, return the RP's rp_info that is an exact match for 'group'
*/
static struct rp_info *
pim_rp_find_exact (struct in_addr rp, struct prefix *group)
{
struct listnode *node;
struct rp_info *rp_info;
for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
{
if (rp.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr &&
prefix_same (&rp_info->group, group))
return rp_info;
}
return NULL;
}
/*
* Given a group, return the rp_info for that group
*/
static struct rp_info *
pim_rp_find_match_group (struct prefix *group)
{
struct listnode *node;
struct rp_info *rp_info;
struct prefix_list *plist;
for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
{
if (rp_info->plist)
{
plist = prefix_list_lookup (AFI_IP, rp_info->plist);
if (plist && prefix_list_apply (plist, group) == PREFIX_PERMIT)
return rp_info;
}
else
{
if (prefix_match (&rp_info->group, group))
return rp_info;
}
}
return NULL;
}
/*
* When the user makes "ip pim rp" configuration changes or if they change the
* prefix-list(s) used by these statements we must tickle the upstream state
* for each group to make them re-lookup who their RP should be.
*
* This is a placeholder function for now.
*/
static void
pim_rp_refresh_group_to_rp_mapping()
{
pim_msdp_i_am_rp_changed();
}
void
pim_rp_prefix_list_update (struct prefix_list *plist)
{
struct listnode *node;
struct rp_info *rp_info;
int refresh_needed = 0;
for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
{
if (rp_info->plist && strcmp(rp_info->plist, prefix_list_name (plist)) == 0)
{
refresh_needed = 1;
break;
}
}
if (refresh_needed)
pim_rp_refresh_group_to_rp_mapping();
}
static int
pim_rp_check_interface_addrs(struct rp_info *rp_info,
struct pim_interface *pim_ifp)
{
struct listnode *node;
struct pim_secondary_addr *sec_addr;
if (pim_ifp->primary_address.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr)
return 1;
if (!pim_ifp->sec_addr_list) {
return 0;
}
for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
if (sec_addr->addr.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr) {
return 1;
}
}
return 0;
}
static void
pim_rp_check_interfaces (struct rp_info *rp_info)
{
struct listnode *node;
struct interface *ifp;
rp_info->i_am_rp = 0;
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
{
struct pim_interface *pim_ifp = ifp->info;
if (!pim_ifp)
continue;
if (pim_rp_check_interface_addrs(rp_info, pim_ifp)) {
rp_info->i_am_rp = 1;
}
}
}
int
pim_rp_new (const char *rp, const char *group_range, const char *plist)
{
int result;
struct rp_info *rp_info;
struct rp_info *rp_all;
struct prefix group_all;
struct listnode *node, *nnode;
struct rp_info *tmp_rp_info;
char buffer[BUFSIZ];
rp_info = XCALLOC (MTYPE_PIM_RP, sizeof (*rp_info));
if (!rp_info)
return PIM_MALLOC_FAIL;
if (group_range == NULL)
result = str2prefix ("224.0.0.0/4", &rp_info->group);
else
result = str2prefix (group_range, &rp_info->group);
if (!result)
{
XFREE (MTYPE_PIM_RP, rp_info);
return PIM_GROUP_BAD_ADDRESS;
}
rp_info->rp.rpf_addr.family = AF_INET;
result = inet_pton (rp_info->rp.rpf_addr.family, rp, &rp_info->rp.rpf_addr.u.prefix4);
if (result <= 0)
{
XFREE (MTYPE_PIM_RP, rp_info);
return PIM_RP_BAD_ADDRESS;
}
if (plist)
{
/*
* Return if the prefix-list is already configured for this RP
*/
if (pim_rp_find_prefix_list (rp_info->rp.rpf_addr.u.prefix4, plist))
{
XFREE (MTYPE_PIM_RP, rp_info);
return PIM_SUCCESS;
}
/*
* Barf if the prefix-list is already configured for an RP
*/
if (pim_rp_prefix_list_used (plist))
{
XFREE (MTYPE_PIM_RP, rp_info);
return PIM_RP_PFXLIST_IN_USE;
}
/*
* Free any existing rp_info entries for this RP
*/
for (ALL_LIST_ELEMENTS (qpim_rp_list, node, nnode, tmp_rp_info))
{
if (rp_info->rp.rpf_addr.u.prefix4.s_addr == tmp_rp_info->rp.rpf_addr.u.prefix4.s_addr)
{
if (tmp_rp_info->plist)
pim_rp_del (rp, NULL, tmp_rp_info->plist);
else
pim_rp_del (rp, prefix2str(&tmp_rp_info->group, buffer, BUFSIZ), NULL);
}
}
rp_info->plist = XSTRDUP(MTYPE_PIM_FILTER_NAME, plist);
}
else
{
str2prefix ("224.0.0.0/4", &group_all);
rp_all = pim_rp_find_match_group(&group_all);
/*
* Barf if group is a non-multicast subnet
*/
if (! prefix_match (&rp_all->group, &rp_info->group))
{
XFREE (MTYPE_PIM_RP, rp_info);
return PIM_GROUP_BAD_ADDRESS;
}
/*
* Remove any prefix-list rp_info entries for this RP
*/
for (ALL_LIST_ELEMENTS (qpim_rp_list, node, nnode, tmp_rp_info))
{
if (tmp_rp_info->plist &&
rp_info->rp.rpf_addr.u.prefix4.s_addr == tmp_rp_info->rp.rpf_addr.u.prefix4.s_addr)
{
pim_rp_del (rp, NULL, tmp_rp_info->plist);
}
}
/*
* Take over the 224.0.0.0/4 group if the rp is INADDR_NONE
*/
if (prefix_same (&rp_all->group, &rp_info->group) &&
pim_rpf_addr_is_inaddr_none (&rp_all->rp))
{
rp_all->rp.rpf_addr = rp_info->rp.rpf_addr;
XFREE (MTYPE_PIM_RP, rp_info);
if (pim_nexthop_lookup (&rp_all->rp.source_nexthop, rp_all->rp.rpf_addr.u.prefix4, 1) != 0)
return PIM_RP_NO_PATH;
pim_rp_check_interfaces (rp_all);
pim_rp_refresh_group_to_rp_mapping();
return PIM_SUCCESS;
}
/*
* Return if the group is already configured for this RP
*/
if (pim_rp_find_exact (rp_info->rp.rpf_addr.u.prefix4, &rp_info->group))
{
XFREE (MTYPE_PIM_RP, rp_info);
return PIM_SUCCESS;
}
/*
* Barf if this group is already covered by some other RP
*/
tmp_rp_info = pim_rp_find_match_group (&rp_info->group);
if (tmp_rp_info)
{
if (tmp_rp_info->plist)
{
XFREE (MTYPE_PIM_RP, rp_info);
return PIM_GROUP_PFXLIST_OVERLAP;
}
else
{
/*
* If the only RP that covers this group is an RP configured for
* 224.0.0.0/4 that is fine, ignore that one. For all others
* though we must return PIM_GROUP_OVERLAP
*/
if (! prefix_same (&group_all, &tmp_rp_info->group))
{
XFREE (MTYPE_PIM_RP, rp_info);
return PIM_GROUP_OVERLAP;
}
}
}
}
listnode_add_sort (qpim_rp_list, rp_info);
if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1) != 0)
return PIM_RP_NO_PATH;
pim_rp_check_interfaces (rp_info);
pim_rp_refresh_group_to_rp_mapping();
return PIM_SUCCESS;
}
int
pim_rp_del (const char *rp, const char *group_range, const char *plist)
{
struct prefix group;
struct in_addr rp_addr;
struct prefix g_all;
struct rp_info *rp_info;
struct rp_info *rp_all;
int result;
if (group_range == NULL)
result = str2prefix ("224.0.0.0/4", &group);
else
result = str2prefix (group_range, &group);
if (!result)
return PIM_GROUP_BAD_ADDRESS;
result = inet_pton (AF_INET, rp, &rp_addr);
if (result <= 0)
return PIM_RP_BAD_ADDRESS;
if (plist)
rp_info = pim_rp_find_prefix_list (rp_addr, plist);
else
rp_info = pim_rp_find_exact (rp_addr, &group);
if (!rp_info)
return PIM_RP_NOT_FOUND;
if (rp_info->plist)
{
XFREE(MTYPE_PIM_FILTER_NAME, rp_info->plist);
rp_info->plist = NULL;
}
str2prefix ("224.0.0.0/4", &g_all);
rp_all = pim_rp_find_match_group (&g_all);
if (rp_all == rp_info)
{
rp_all->rp.rpf_addr.family = AF_INET;
rp_all->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE;
rp_all->i_am_rp = 0;
return PIM_SUCCESS;
}
listnode_delete (qpim_rp_list, rp_info);
pim_rp_refresh_group_to_rp_mapping();
return PIM_SUCCESS;
}
int
pim_rp_setup (void)
{
struct listnode *node;
struct rp_info *rp_info;
int ret = 0;
for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
{
if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
continue;
if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1) != 0)
{
if (PIM_DEBUG_PIM_TRACE)
zlog_debug ("Unable to lookup nexthop for rp specified");
ret++;
}
}
if (ret)
return 0;
return 1;
}
/*
* Checks to see if we should elect ourself the actual RP when new if
* addresses are added against an interface.
*/
void
pim_rp_check_on_if_add(struct pim_interface *pim_ifp)
{
struct listnode *node;
struct rp_info *rp_info;
bool i_am_rp_changed = false;
if (qpim_rp_list == NULL)
return;
for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info)) {
if (pim_rpf_addr_is_inaddr_none (&rp_info->rp))
continue;
/* if i_am_rp is already set nothing to be done (adding new addresses
* is not going to make a difference). */
if (rp_info->i_am_rp) {
continue;
}
if (pim_rp_check_interface_addrs(rp_info, pim_ifp)) {
i_am_rp_changed = true;
rp_info->i_am_rp = 1;
if (PIM_DEBUG_ZEBRA) {
char rp[PREFIX_STRLEN];
pim_addr_dump("<rp?>", &rp_info->rp.rpf_addr, rp, sizeof(rp));
zlog_debug("%s: %s: i am rp", __func__, rp);
}
}
}
if (i_am_rp_changed) {
pim_msdp_i_am_rp_changed();
}
}
/* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
* are removed. Removing numbers is an uncommon event in an active network
* so I have made no attempt to optimize it. */
void
pim_i_am_rp_re_evaluate(void)
{
struct listnode *node;
struct rp_info *rp_info;
bool i_am_rp_changed = false;
int old_i_am_rp;
if (qpim_rp_list == NULL)
return;
for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) {
if (pim_rpf_addr_is_inaddr_none(&rp_info->rp))
continue;
old_i_am_rp = rp_info->i_am_rp;
pim_rp_check_interfaces(rp_info);
if (old_i_am_rp != rp_info->i_am_rp) {
i_am_rp_changed = true;
if (PIM_DEBUG_ZEBRA) {
char rp[PREFIX_STRLEN];
pim_addr_dump("<rp?>", &rp_info->rp.rpf_addr, rp, sizeof(rp));
if (rp_info->i_am_rp) {
zlog_debug("%s: %s: i am rp", __func__, rp);
} else {
zlog_debug("%s: %s: i am no longer rp", __func__, rp);
}
}
}
}
if (i_am_rp_changed) {
pim_msdp_i_am_rp_changed();
}
} }
/* /*
@ -73,7 +622,20 @@ pim_rp_check_rp (struct in_addr old, struct in_addr new)
int int
pim_rp_i_am_rp (struct in_addr group) pim_rp_i_am_rp (struct in_addr group)
{ {
return i_am_rp; struct prefix g;
struct rp_info *rp_info;
memset (&g, 0, sizeof (g));
g.family = AF_INET;
g.prefixlen = 32;
g.u.prefix4 = group;
rp_info = pim_rp_find_match_group (&g);
if (rp_info)
return rp_info->i_am_rp;
return 0;
} }
/* /*
@ -84,11 +646,24 @@ pim_rp_i_am_rp (struct in_addr group)
struct pim_rpf * struct pim_rpf *
pim_rp_g (struct in_addr group) pim_rp_g (struct in_addr group)
{ {
/* struct prefix g;
* For staticly configured RP, it is always the qpim_rp struct rp_info *rp_info;
*/
pim_nexthop_lookup(&qpim_rp.source_nexthop, qpim_rp.rpf_addr, NULL); memset (&g, 0, sizeof (g));
return(&qpim_rp); g.family = AF_INET;
g.prefixlen = 32;
g.u.prefix4 = group;
rp_info = pim_rp_find_match_group (&g);
if (rp_info)
{
pim_nexthop_lookup(&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1);
return (&rp_info->rp);
}
// About to Go Down
return NULL;
} }
/* /*
@ -100,16 +675,168 @@ pim_rp_g (struct in_addr group)
* *
*/ */
int int
pim_rp_set_upstream_addr (struct in_addr *up, struct in_addr source) pim_rp_set_upstream_addr (struct in_addr *up, struct in_addr source, struct in_addr group)
{ {
if ((qpim_rp.rpf_addr.s_addr == INADDR_NONE) && (source.s_addr == INADDR_ANY)) struct rp_info *rp_info;
struct prefix g;
memset (&g, 0, sizeof (g));
g.family = AF_INET;
g.prefixlen = 32;
g.u.prefix4 = group;
rp_info = pim_rp_find_match_group (&g);
if ((pim_rpf_addr_is_inaddr_none (&rp_info->rp)) && (source.s_addr == INADDR_ANY))
{ {
if (PIM_DEBUG_PIM_TRACE) if (PIM_DEBUG_PIM_TRACE)
zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__); zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__);
return 0; return 0;
} }
*up = (source.s_addr == INADDR_ANY) ? qpim_rp.rpf_addr : source; *up = (source.s_addr == INADDR_ANY) ? rp_info->rp.rpf_addr.u.prefix4 : source;
return 1; return 1;
} }
int
pim_rp_config_write (struct vty *vty)
{
struct listnode *node;
struct rp_info *rp_info;
char rp_buffer[32];
char group_buffer[32];
int count = 0;
for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
{
if (pim_rpf_addr_is_inaddr_none (&rp_info->rp))
continue;
if (rp_info->plist)
vty_out(vty, "ip pim rp %s prefix-list %s%s",
inet_ntop(AF_INET, &rp_info->rp.rpf_addr.u.prefix4, rp_buffer, 32),
rp_info->plist, VTY_NEWLINE);
else
vty_out(vty, "ip pim rp %s %s%s",
inet_ntop(AF_INET, &rp_info->rp.rpf_addr.u.prefix4, rp_buffer, 32),
prefix2str(&rp_info->group, group_buffer, 32), VTY_NEWLINE);
count++;
}
return count;
}
int
pim_rp_check_is_my_ip_address (struct in_addr group, struct in_addr dest_addr)
{
struct rp_info *rp_info;
struct prefix g;
memset (&g, 0, sizeof (g));
g.family = AF_INET;
g.prefixlen = 32;
g.u.prefix4 = group;
rp_info = pim_rp_find_match_group (&g);
/*
* See if we can short-cut some?
* This might not make sense if we ever leave a static RP
* type of configuration.
* Note - Premature optimization might bite our patooeys' here.
*/
if (I_am_RP(group))
{
if (dest_addr.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr)
return 1;
}
if (if_lookup_exact_address (&dest_addr, AF_INET))
return 1;
return 0;
}
void
pim_rp_show_information (struct vty *vty, u_char uj)
{
struct rp_info *rp_info;
struct rp_info *prev_rp_info = NULL;
struct listnode *node;
json_object *json = NULL;
json_object *json_rp_rows = NULL;
json_object *json_row = NULL;
if (uj)
json = json_object_new_object();
else
vty_out (vty, "RP address group/prefix-list OIF I am RP%s", VTY_NEWLINE);
for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
{
if (!pim_rpf_addr_is_inaddr_none (&rp_info->rp))
{
char buf[48];
if (uj)
{
/*
* If we have moved on to a new RP then add the entry for the previous RP
*/
if (prev_rp_info &&
prev_rp_info->rp.rpf_addr.u.prefix4.s_addr != rp_info->rp.rpf_addr.u.prefix4.s_addr)
{
json_object_object_add(json, inet_ntoa (prev_rp_info->rp.rpf_addr.u.prefix4), json_rp_rows);
json_rp_rows = NULL;
}
if (!json_rp_rows)
json_rp_rows = json_object_new_array();
json_row = json_object_new_object();
if (rp_info->rp.source_nexthop.interface)
json_object_string_add(json_row, "outboundInterface", rp_info->rp.source_nexthop.interface->name);
if (rp_info->i_am_rp)
json_object_boolean_true_add(json_row, "iAmRP");
if (rp_info->plist)
json_object_string_add(json_row, "prefixList", rp_info->plist);
else
json_object_string_add(json_row, "group", prefix2str(&rp_info->group, buf, 48));
json_object_array_add(json_rp_rows, json_row);
}
else
{
vty_out (vty, "%-15s ", inet_ntoa (rp_info->rp.rpf_addr.u.prefix4));
if (rp_info->plist)
vty_out (vty, "%-18s ", rp_info->plist);
else
vty_out (vty, "%-18s ", prefix2str(&rp_info->group, buf, 48));
if (rp_info->rp.source_nexthop.interface)
vty_out (vty, "%-10s ", rp_info->rp.source_nexthop.interface->name);
else
vty_out (vty, "%-10s ", "(Unknown)");
if (rp_info->i_am_rp)
vty_out (vty, "yes%s", VTY_NEWLINE);
else
vty_out (vty, "no%s", VTY_NEWLINE);
}
prev_rp_info = rp_info;
}
}
if (uj) {
if (prev_rp_info && json_rp_rows)
json_object_object_add(json, inet_ntoa (prev_rp_info->rp.rpf_addr.u.prefix4), json_rp_rows);
vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
json_object_free(json);
}
}

View File

@ -21,11 +21,29 @@
#ifndef PIM_RP_H #ifndef PIM_RP_H
#define PIM_RP_H #define PIM_RP_H
void pim_rp_check_rp (struct in_addr old, struct in_addr new); void pim_rp_init (void);
void pim_rp_free (void);
int pim_rp_new (const char *rp, const char *group, const char *plist);
int pim_rp_del (const char *rp, const char *group, const char *plist);
void pim_rp_prefix_list_update (struct prefix_list *plist);
int pim_rp_config_write (struct vty *vty);
int pim_rp_setup (void);
int pim_rp_i_am_rp (struct in_addr group); int pim_rp_i_am_rp (struct in_addr group);
int pim_rp_set_upstream_addr (struct in_addr *up, struct in_addr source); void pim_rp_check_on_if_add(struct pim_interface *pim_ifp);
void pim_i_am_rp_re_evaluate(void);
int pim_rp_check_is_my_ip_address (struct in_addr group, struct in_addr dest_addr);
int pim_rp_set_upstream_addr (struct in_addr *up, struct in_addr source, struct in_addr group);
struct pim_rpf *pim_rp_g (struct in_addr group); struct pim_rpf *pim_rp_g (struct in_addr group);
#define I_am_RP(G) pim_rp_i_am_rp ((G)) #define I_am_RP(G) pim_rp_i_am_rp ((G))
#define RP(G) pim_rp_g ((G)) #define RP(G) pim_rp_g ((G))
void pim_rp_show_information (struct vty *vty, u_char uj);
#endif #endif

View File

@ -33,108 +33,160 @@
#include "pim_iface.h" #include "pim_iface.h"
#include "pim_zlookup.h" #include "pim_zlookup.h"
#include "pim_ifchannel.h" #include "pim_ifchannel.h"
#include "pim_time.h"
static long long last_route_change_time = -1;
long long nexthop_lookups_avoided = 0;
static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up); static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up);
int pim_nexthop_lookup(struct pim_nexthop *nexthop, void
struct in_addr addr, struct interface *incoming) pim_rpf_set_refresh_time (void)
{ {
struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE]; last_route_change_time = pim_time_monotonic_usec();
if (PIM_DEBUG_TRACE)
zlog_debug ("%s: New last route change time: %lld",
__PRETTY_FUNCTION__, last_route_change_time);
}
int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, int neighbor_needed)
{
struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
int num_ifindex; int num_ifindex;
struct interface *ifp; struct interface *ifp = NULL;
int first_ifindex; ifindex_t first_ifindex = 0;
int found = 0;
int i = 0;
memset (nexthop_tab, 0, sizeof (struct pim_zlookup_nexthop) * PIM_NEXTHOP_IFINDEX_TAB_SIZE); if ((nexthop->last_lookup.s_addr == addr.s_addr) &&
(nexthop->last_lookup_time > last_route_change_time))
if (!incoming)
{ {
num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab, if (PIM_DEBUG_TRACE)
PIM_NEXTHOP_IFINDEX_TAB_SIZE, {
addr, PIM_NEXTHOP_LOOKUP_MAX); char addr_str[INET_ADDRSTRLEN];
if (num_ifindex < 1) { pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
char addr_str[100]; zlog_debug ("%s: Using last lookup for %s at %lld, %lld",
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); __PRETTY_FUNCTION__,
zlog_warn("%s %s: could not find nexthop ifindex for address %s", addr_str,
__FILE__, __PRETTY_FUNCTION__, nexthop->last_lookup_time,
addr_str); last_route_change_time);
return -1; }
} nexthop_lookups_avoided++;
return 0;
first_ifindex = nexthop_tab[0].ifindex;
if (num_ifindex > 1) {
char addr_str[100];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
__FILE__, __PRETTY_FUNCTION__,
num_ifindex, addr_str, first_ifindex);
/* debug warning only, do not return */
}
ifp = if_lookup_by_index(first_ifindex);
if (!ifp) {
char addr_str[100];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_warn("%s %s: could not find interface for ifindex %d (address %s)",
__FILE__, __PRETTY_FUNCTION__,
first_ifindex, addr_str);
return -2;
}
} }
else else
{ {
ifp = incoming; if (PIM_DEBUG_TRACE)
first_ifindex = ifp->ifindex; {
char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug ("%s: Looking up: %s, last lookup time: %lld, %lld",
__PRETTY_FUNCTION__,
addr_str,
nexthop->last_lookup_time,
last_route_change_time);
}
} }
if (!ifp->info) { memset (nexthop_tab, 0, sizeof (struct pim_zlookup_nexthop) * MULTIPATH_NUM);
char addr_str[100]; num_ifindex = zclient_lookup_nexthop(nexthop_tab,
MULTIPATH_NUM,
addr, PIM_NEXTHOP_LOOKUP_MAX);
if (num_ifindex < 1) {
char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_warn("%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)", zlog_warn("%s %s: could not find nexthop ifindex for address %s",
__PRETTY_FUNCTION__, __FILE__, __PRETTY_FUNCTION__,
ifp->name, first_ifindex, addr_str); addr_str);
/* debug warning only, do not return */ return -1;
} }
if (PIM_DEBUG_PIM_TRACE) { while (!found && (i < num_ifindex))
char nexthop_str[100]; {
char addr_str[100]; first_ifindex = nexthop_tab[i].ifindex;
pim_inet4_dump("<nexthop?>", nexthop_tab[0].nexthop_addr, nexthop_str, sizeof(nexthop_str));
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s %s: found nexthop %s for address %s: interface %s ifindex=%d metric=%d pref=%d",
__FILE__, __PRETTY_FUNCTION__,
nexthop_str, addr_str,
ifp->name, first_ifindex,
nexthop_tab[0].route_metric,
nexthop_tab[0].protocol_distance);
}
/* update nextop data */ ifp = if_lookup_by_index(first_ifindex);
nexthop->interface = ifp; if (!ifp)
nexthop->mrib_nexthop_addr = nexthop_tab[0].nexthop_addr; {
nexthop->mrib_metric_preference = nexthop_tab[0].protocol_distance; if (PIM_DEBUG_ZEBRA)
nexthop->mrib_route_metric = nexthop_tab[0].route_metric; {
char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s %s: could not find interface for ifindex %d (address %s)",
__FILE__, __PRETTY_FUNCTION__,
first_ifindex, addr_str);
}
i++;
continue;
}
return 0; if (!ifp->info)
{
if (PIM_DEBUG_ZEBRA)
{
char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)",
__PRETTY_FUNCTION__,
ifp->name, first_ifindex, addr_str);
}
i++;
}
else if (neighbor_needed && !pim_if_connected_to_source (ifp, addr))
{
struct pim_neighbor *nbr;
nbr = pim_neighbor_find (ifp, nexthop_tab[i].nexthop_addr.u.prefix4);
if (PIM_DEBUG_PIM_TRACE_DETAIL)
zlog_debug ("ifp name: %s, pim nbr: %p", ifp->name, nbr);
if (!nbr && !if_is_loopback (ifp))
i++;
else
found = 1;
}
else
found = 1;
}
if (found)
{
if (PIM_DEBUG_ZEBRA) {
char nexthop_str[PREFIX_STRLEN];
char addr_str[INET_ADDRSTRLEN];
pim_addr_dump("<nexthop?>", &nexthop_tab[i].nexthop_addr, nexthop_str, sizeof(nexthop_str));
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s %s: found nexthop %s for address %s: interface %s ifindex=%d metric=%d pref=%d",
__FILE__, __PRETTY_FUNCTION__,
nexthop_str, addr_str,
ifp->name, first_ifindex,
nexthop_tab[i].route_metric,
nexthop_tab[i].protocol_distance);
}
/* update nextop data */
nexthop->interface = ifp;
nexthop->mrib_nexthop_addr = nexthop_tab[i].nexthop_addr;
nexthop->mrib_metric_preference = nexthop_tab[i].protocol_distance;
nexthop->mrib_route_metric = nexthop_tab[i].route_metric;
nexthop->last_lookup = addr;
nexthop->last_lookup_time = pim_time_monotonic_usec();
return 0;
}
else
return -1;
} }
static int nexthop_mismatch(const struct pim_nexthop *nh1, static int nexthop_mismatch(const struct pim_nexthop *nh1,
const struct pim_nexthop *nh2) const struct pim_nexthop *nh2)
{ {
return (nh1->interface != nh2->interface) return (nh1->interface != nh2->interface) ||
|| (nh1->mrib_nexthop_addr.u.prefix4.s_addr != nh2->mrib_nexthop_addr.u.prefix4.s_addr) ||
(nh1->mrib_nexthop_addr.s_addr != nh2->mrib_nexthop_addr.s_addr) (nh1->mrib_metric_preference != nh2->mrib_metric_preference) ||
||
(nh1->mrib_metric_preference != nh2->mrib_metric_preference)
||
(nh1->mrib_route_metric != nh2->mrib_route_metric); (nh1->mrib_route_metric != nh2->mrib_route_metric);
} }
enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct in_addr *old_rpf_addr)
struct in_addr *old_rpf_addr,
struct interface *incoming)
{ {
struct in_addr save_rpf_addr; struct prefix save_rpf_addr;
struct pim_nexthop save_nexthop; struct pim_nexthop save_nexthop;
struct pim_rpf *rpf = &up->rpf; struct pim_rpf *rpf = &up->rpf;
@ -142,36 +194,31 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up,
save_rpf_addr = rpf->rpf_addr; /* detect change in RPF'(S,G) */ save_rpf_addr = rpf->rpf_addr; /* detect change in RPF'(S,G) */
if (pim_nexthop_lookup(&rpf->source_nexthop, if (pim_nexthop_lookup(&rpf->source_nexthop,
up->upstream_addr, incoming)) { up->upstream_addr,
!PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) &&
!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags))) {
return PIM_RPF_FAILURE; return PIM_RPF_FAILURE;
} }
rpf->rpf_addr = pim_rpf_find_rpf_addr(up); rpf->rpf_addr.family = AF_INET;
if (PIM_INADDR_IS_ANY(rpf->rpf_addr) && PIM_DEBUG_PIM_EVENTS) { rpf->rpf_addr.u.prefix4 = pim_rpf_find_rpf_addr(up);
if (pim_rpf_addr_is_inaddr_any(rpf) && PIM_DEBUG_ZEBRA) {
/* RPF'(S,G) not found */ /* RPF'(S,G) not found */
char src_str[100]; zlog_debug("%s %s: RPF'%s not found: won't send join upstream",
char grp_str[100];
pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
zlog_debug("%s %s: RPF'(%s,%s) not found: won't send join upstream",
__FILE__, __PRETTY_FUNCTION__, __FILE__, __PRETTY_FUNCTION__,
src_str, grp_str); up->sg_str);
/* warning only */ /* warning only */
} }
/* detect change in pim_nexthop */ /* detect change in pim_nexthop */
if (nexthop_mismatch(&rpf->source_nexthop, &save_nexthop)) { if (nexthop_mismatch(&rpf->source_nexthop, &save_nexthop)) {
if (PIM_DEBUG_PIM_EVENTS) { if (PIM_DEBUG_ZEBRA) {
char src_str[100]; char nhaddr_str[PREFIX_STRLEN];
char grp_str[100]; pim_addr_dump("<addr?>", &rpf->source_nexthop.mrib_nexthop_addr, nhaddr_str, sizeof(nhaddr_str));
char nhaddr_str[100]; zlog_debug("%s %s: (S,G)=%s source nexthop now is: interface=%s address=%s pref=%d metric=%d",
pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
pim_inet4_dump("<addr?>", rpf->source_nexthop.mrib_nexthop_addr, nhaddr_str, sizeof(nhaddr_str));
zlog_debug("%s %s: (S,G)=(%s,%s) source nexthop now is: interface=%s address=%s pref=%d metric=%d",
__FILE__, __PRETTY_FUNCTION__, __FILE__, __PRETTY_FUNCTION__,
src_str, grp_str, up->sg_str,
rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "<ifname?>", rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "<ifname?>",
nhaddr_str, nhaddr_str,
rpf->source_nexthop.mrib_metric_preference, rpf->source_nexthop.mrib_metric_preference,
@ -186,14 +233,10 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up,
/* detect change in RPF_interface(S) */ /* detect change in RPF_interface(S) */
if (save_nexthop.interface != rpf->source_nexthop.interface) { if (save_nexthop.interface != rpf->source_nexthop.interface) {
if (PIM_DEBUG_PIM_EVENTS) { if (PIM_DEBUG_ZEBRA) {
char src_str[100]; zlog_debug("%s %s: (S,G)=%s RPF_interface(S) changed from %s to %s",
char grp_str[100];
pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
zlog_debug("%s %s: (S,G)=(%s,%s) RPF_interface(S) changed from %s to %s",
__FILE__, __PRETTY_FUNCTION__, __FILE__, __PRETTY_FUNCTION__,
src_str, grp_str, up->sg_str,
save_nexthop.interface ? save_nexthop.interface->name : "<oldif?>", save_nexthop.interface ? save_nexthop.interface->name : "<oldif?>",
rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "<newif?>"); rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "<newif?>");
/* warning only */ /* warning only */
@ -203,11 +246,11 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up,
} }
/* detect change in RPF'(S,G) */ /* detect change in RPF'(S,G) */
if (save_rpf_addr.s_addr != rpf->rpf_addr.s_addr) { if (save_rpf_addr.u.prefix4.s_addr != rpf->rpf_addr.u.prefix4.s_addr) {
/* return old rpf to caller ? */ /* return old rpf to caller ? */
if (old_rpf_addr) if (old_rpf_addr)
*old_rpf_addr = save_rpf_addr; *old_rpf_addr = save_rpf_addr.u.prefix4;
return PIM_RPF_CHANGED; return PIM_RPF_CHANGED;
} }
@ -237,20 +280,16 @@ static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up)
struct in_addr rpf_addr; struct in_addr rpf_addr;
if (!up->rpf.source_nexthop.interface) { if (!up->rpf.source_nexthop.interface) {
char src_str[100]; zlog_warn("%s: missing RPF interface for upstream (S,G)=%s",
char grp_str[100];
pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
zlog_warn("%s: missing RPF interface for upstream (S,G)=(%s,%s)",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
src_str, grp_str); up->sg_str);
rpf_addr.s_addr = PIM_NET_INADDR_ANY; rpf_addr.s_addr = PIM_NET_INADDR_ANY;
return rpf_addr; return rpf_addr;
} }
rpf_ch = pim_ifchannel_find(up->rpf.source_nexthop.interface, rpf_ch = pim_ifchannel_find(up->rpf.source_nexthop.interface,
up->source_addr, up->group_addr); &up->sg);
if (rpf_ch) { if (rpf_ch) {
if (rpf_ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) { if (rpf_ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
return rpf_ch->ifassert_winner; return rpf_ch->ifassert_winner;
@ -260,7 +299,7 @@ static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up)
/* return NBR( RPF_interface(S), MRIB.next_hop( S ) ) */ /* return NBR( RPF_interface(S), MRIB.next_hop( S ) ) */
neigh = pim_if_find_neighbor(up->rpf.source_nexthop.interface, neigh = pim_if_find_neighbor(up->rpf.source_nexthop.interface,
up->rpf.source_nexthop.mrib_nexthop_addr); up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4);
if (neigh) if (neigh)
rpf_addr = neigh->source_addr; rpf_addr = neigh->source_addr;
else else
@ -268,3 +307,52 @@ static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up)
return rpf_addr; return rpf_addr;
} }
int
pim_rpf_addr_is_inaddr_none (struct pim_rpf *rpf)
{
switch (rpf->rpf_addr.family)
{
case AF_INET:
return rpf->rpf_addr.u.prefix4.s_addr == INADDR_NONE;
break;
case AF_INET6:
zlog_warn ("%s: v6 Unimplmeneted", __PRETTY_FUNCTION__);
return 1;
break;
default:
return 0;
break;
}
return 0;
}
int
pim_rpf_addr_is_inaddr_any (struct pim_rpf *rpf)
{
switch (rpf->rpf_addr.family)
{
case AF_INET:
return rpf->rpf_addr.u.prefix4.s_addr == INADDR_ANY;
break;
case AF_INET6:
zlog_warn ("%s: v6 Unimplmented", __PRETTY_FUNCTION__);
return 1;
break;
default:
return 0;
break;
}
return 0;
}
int
pim_rpf_is_same (struct pim_rpf *rpf1, struct pim_rpf *rpf2)
{
if (rpf1->source_nexthop.interface == rpf2->source_nexthop.interface)
return 1;
return 0;
}

View File

@ -26,10 +26,48 @@
#include "pim_upstream.h" #include "pim_upstream.h"
#include "pim_neighbor.h" #include "pim_neighbor.h"
int pim_nexthop_lookup(struct pim_nexthop *nexthop, /*
struct in_addr addr, struct interface *incoming); RFC 4601:
enum pim_rpf_result pim_rpf_update(struct pim_upstream *up,
struct in_addr *old_rpf_addr,
struct interface *incoming);
Metric Preference
Preference value assigned to the unicast routing protocol that
provided the route to the multicast source or Rendezvous-Point.
Metric
The unicast routing table metric associated with the route used to
reach the multicast source or Rendezvous-Point. The metric is in
units applicable to the unicast routing protocol used.
*/
struct pim_nexthop {
struct in_addr last_lookup;
long long last_lookup_time;
struct interface *interface; /* RPF_interface(S) */
struct prefix mrib_nexthop_addr; /* MRIB.next_hop(S) */
uint32_t mrib_metric_preference; /* MRIB.pref(S) */
uint32_t mrib_route_metric; /* MRIB.metric(S) */
};
struct pim_rpf {
struct pim_nexthop source_nexthop;
struct prefix rpf_addr; /* RPF'(S,G) */
};
enum pim_rpf_result {
PIM_RPF_OK = 0,
PIM_RPF_CHANGED,
PIM_RPF_FAILURE
};
struct pim_upstream;
extern long long nexthop_lookups_avoided;
int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, int neighbor_needed);
enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct in_addr *old_rpf_addr);
int pim_rpf_addr_is_inaddr_none (struct pim_rpf *rpf);
int pim_rpf_addr_is_inaddr_any (struct pim_rpf *rpf);
int pim_rpf_is_same (struct pim_rpf *rpf1, struct pim_rpf *rpf2);
void pim_rpf_set_refresh_time (void);
#endif /* PIM_RPF_H */ #endif /* PIM_RPF_H */

View File

@ -44,7 +44,8 @@
/* GLOBAL VARS */ /* GLOBAL VARS */
extern struct zebra_privs_t pimd_privs; extern struct zebra_privs_t pimd_privs;
int pim_socket_raw(int protocol) int
pim_socket_raw (int protocol)
{ {
int fd; int fd;
@ -67,8 +68,58 @@ int pim_socket_raw(int protocol)
return fd; return fd;
} }
int
pim_socket_ip_hdr (int fd)
{
const int on = 1;
int ret;
if (pimd_privs.change (ZPRIVS_RAISE))
zlog_err ("%s: could not raise privs, %s",
__PRETTY_FUNCTION__, safe_strerror (errno));
ret = setsockopt (fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on));
if (pimd_privs.change (ZPRIVS_LOWER))
zlog_err ("%s: could not lower privs, %s",
__PRETTY_FUNCTION__, safe_strerror (errno));
return ret;
}
/*
* Given a socket and a interface,
* Bind that socket to that interface
*/
int
pim_socket_bind (int fd, struct interface *ifp)
{
int ret = 0;
#ifdef SO_BINDTODEVICE
if (pimd_privs.change (ZPRIVS_RAISE))
zlog_err ("%s: could not raise privs, %s",
__PRETTY_FUNCTION__, safe_strerror (errno));
ret = setsockopt (fd, SOL_SOCKET,
SO_BINDTODEVICE, ifp->name, strlen (ifp->name));
if (pimd_privs.change (ZPRIVS_LOWER))
zlog_err ("%s: could not lower privs, %s",
__PRETTY_FUNCTION__, safe_strerror (errno));
#endif
return ret;
}
int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, u_char loop) int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, u_char loop)
{ {
int rcvbuf = 1024 * 1024 * 8;
#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
struct ip_mreqn mreq;
#else
struct ip_mreq mreq;
#endif
int fd; int fd;
fd = pim_socket_raw(protocol); fd = pim_socket_raw(protocol);
@ -86,17 +137,7 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, u_char lo
ifp = if_lookup_by_index_vrf (ifindex, VRF_DEFAULT); ifp = if_lookup_by_index_vrf (ifindex, VRF_DEFAULT);
if (pimd_privs.change (ZPRIVS_RAISE)) ret = pim_socket_bind (fd, ifp);
zlog_err ("%s: could not raise privs, %s",
__PRETTY_FUNCTION__, safe_strerror (errno));
ret = setsockopt (fd, SOL_SOCKET,
SO_BINDTODEVICE, ifp->name, strlen (ifp->name));
if (pimd_privs.change (ZPRIVS_LOWER))
zlog_err ("%s: could not lower privs, %s",
__PRETTY_FUNCTION__, safe_strerror (errno));
if (ret) if (ret)
{ {
zlog_warn("Could not set fd: %d for interface: %s to device", zlog_warn("Could not set fd: %d for interface: %s to device",
@ -180,14 +221,28 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, u_char lo
return PIM_SOCK_ERR_LOOP; return PIM_SOCK_ERR_LOOP;
} }
memset (&mreq, 0, sizeof (mreq));
#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
mreq.imr_ifindex = ifindex;
#else
/*
* I am not sure what to do here yet for *BSD
*/
//mreq.imr_interface = ifindex;
#endif
if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
(void *) &ifaddr, sizeof(ifaddr))) { (void *) &mreq, sizeof(mreq))) {
zlog_warn("Could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s", zlog_warn("Could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s",
fd, errno, safe_strerror(errno)); fd, errno, safe_strerror(errno));
close(fd); close(fd);
return PIM_SOCK_ERR_IFACE; return PIM_SOCK_ERR_IFACE;
} }
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)))
zlog_warn("%s: Failure to set buffer size to %d",
__PRETTY_FUNCTION__, rcvbuf);
{ {
long flags; long flags;
@ -232,8 +287,8 @@ int pim_socket_join(int fd, struct in_addr group,
ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &opt, sizeof(opt)); ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &opt, sizeof(opt));
if (ret) { if (ret) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char ifaddr_str[100]; char ifaddr_str[INET_ADDRSTRLEN];
if (!inet_ntop(AF_INET, &group, group_str , sizeof(group_str))) if (!inet_ntop(AF_INET, &group, group_str , sizeof(group_str)))
sprintf(group_str, "<group?>"); sprintf(group_str, "<group?>");
if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str , sizeof(ifaddr_str))) if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str , sizeof(ifaddr_str)))
@ -245,8 +300,8 @@ int pim_socket_join(int fd, struct in_addr group,
} }
if (PIM_DEBUG_TRACE) { if (PIM_DEBUG_TRACE) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char ifaddr_str[100]; char ifaddr_str[INET_ADDRSTRLEN];
if (!inet_ntop(AF_INET, &group, group_str , sizeof(group_str))) if (!inet_ntop(AF_INET, &group, group_str , sizeof(group_str)))
sprintf(group_str, "<group?>"); sprintf(group_str, "<group?>");
if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str , sizeof(ifaddr_str))) if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str , sizeof(ifaddr_str)))
@ -265,15 +320,14 @@ int pim_socket_join_source(int fd, ifindex_t ifindex,
const char *ifname) const char *ifname)
{ {
if (pim_igmp_join_source(fd, ifindex, group_addr, source_addr)) { if (pim_igmp_join_source(fd, ifindex, group_addr, source_addr)) {
int e = errno; char group_str[INET_ADDRSTRLEN];
char group_str[100]; char source_str[INET_ADDRSTRLEN];
char source_str[100];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s", zlog_warn("%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
fd, group_str, source_str, ifindex, ifname, fd, group_str, source_str, ifindex, ifname,
e, safe_strerror(e)); errno, safe_strerror(errno));
return -1; return -1;
} }
@ -298,17 +352,14 @@ int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
if (to) { if (to) {
struct sockaddr_in si; struct sockaddr_in si;
socklen_t si_len = sizeof(si); socklen_t si_len = sizeof(si);
((struct sockaddr_in *) to)->sin_family = AF_INET;
if (pim_socket_getsockname(fd, (struct sockaddr *) &si, &si_len)) { memset (&si, 0, sizeof (si));
((struct sockaddr_in *) to)->sin_port = ntohs(0); to->sin_family = AF_INET;
((struct sockaddr_in *) to)->sin_addr.s_addr = ntohl(0);
} pim_socket_getsockname(fd, (struct sockaddr *) &si, &si_len);
else {
((struct sockaddr_in *) to)->sin_port = si.sin_port; to->sin_port = si.sin_port;
((struct sockaddr_in *) to)->sin_addr = si.sin_addr; to->sin_addr = si.sin_addr;
}
if (tolen) if (tolen)
*tolen = sizeof(si); *tolen = sizeof(si);
@ -346,14 +397,6 @@ int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
if (ifindex) if (ifindex)
*ifindex = i->ipi_ifindex; *ifindex = i->ipi_ifindex;
if (to && PIM_DEBUG_PACKETS) {
char to_str[100];
pim_inet4_dump("<to?>", to->sin_addr, to_str, sizeof(to_str));
zlog_debug("%s: HAVE_IP_PKTINFO to=%s,%d",
__PRETTY_FUNCTION__,
to_str, ntohs(to->sin_port));
}
break; break;
} }
#endif #endif
@ -366,14 +409,6 @@ int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
if (tolen) if (tolen)
*tolen = sizeof(struct sockaddr_in); *tolen = sizeof(struct sockaddr_in);
if (to && PIM_DEBUG_PACKETS) {
char to_str[100];
pim_inet4_dump("<to?>", to->sin_addr, to_str, sizeof(to_str));
zlog_debug("%s: HAVE_IP_RECVDSTADDR to=%s,%d",
__PRETTY_FUNCTION__,
to_str, ntohs(to->sin_port));
}
break; break;
} }
#endif #endif

View File

@ -36,6 +36,8 @@
#define PIM_SOCK_ERR_NAME (-10) /* Socket name (getsockname) */ #define PIM_SOCK_ERR_NAME (-10) /* Socket name (getsockname) */
#define PIM_SOCK_ERR_BIND (-11) /* Can't bind to interface */ #define PIM_SOCK_ERR_BIND (-11) /* Can't bind to interface */
int pim_socket_bind (int fd, struct interface *ifp);
int pim_socket_ip_hdr (int fd);
int pim_socket_raw(int protocol); int pim_socket_raw(int protocol);
int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, u_char loop); int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, u_char loop);
int pim_socket_join(int fd, struct in_addr group, int pim_socket_join(int fd, struct in_addr group,

View File

@ -25,11 +25,10 @@
#include "memory.h" #include "memory.h"
#include "sockopt.h" #include "sockopt.h"
#include "pimd.h"
#include "pim_ssmpingd.h" #include "pim_ssmpingd.h"
#include "pim_time.h" #include "pim_time.h"
#include "pim_sock.h" #include "pim_sock.h"
#include "pim_str.h"
#include "pimd.h"
static const char * const PIM_SSMPINGD_REPLY_GROUP = "232.43.211.234"; static const char * const PIM_SSMPINGD_REPLY_GROUP = "232.43.211.234";
@ -96,7 +95,7 @@ static int ssmpingd_socket(struct in_addr addr, int port, int mttl)
sockaddr.sin_port = htons(port); sockaddr.sin_port = htons(port);
if (bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) { if (bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
char addr_str[100]; char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_warn("%s: bind(fd=%d,addr=%s,port=%d,len=%zu) failure: errno=%d: %s", zlog_warn("%s: bind(fd=%d,addr=%s,port=%d,len=%zu) failure: errno=%d: %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -195,12 +194,11 @@ static void ssmpingd_delete(struct ssmpingd_sock *ss)
THREAD_OFF(ss->t_sock_read); THREAD_OFF(ss->t_sock_read);
if (close(ss->sock_fd)) { if (close(ss->sock_fd)) {
int e = errno; char source_str[INET_ADDRSTRLEN];
char source_str[100];
pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str));
zlog_warn("%s: failure closing ssmpingd sock_fd=%d for source %s: errno=%d: %s", zlog_warn("%s: failure closing ssmpingd sock_fd=%d for source %s: errno=%d: %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
ss->sock_fd, source_str, e, safe_strerror(e)); ss->sock_fd, source_str, errno, safe_strerror(errno));
/* warning only */ /* warning only */
} }
@ -219,14 +217,13 @@ static void ssmpingd_sendto(struct ssmpingd_sock *ss,
sent = sendto(ss->sock_fd, buf, len, MSG_DONTWAIT, sent = sendto(ss->sock_fd, buf, len, MSG_DONTWAIT,
(struct sockaddr *)&to, tolen); (struct sockaddr *)&to, tolen);
if (sent != len) { if (sent != len) {
int e = errno; char to_str[INET_ADDRSTRLEN];
char to_str[100];
pim_inet4_dump("<to?>", to.sin_addr, to_str, sizeof(to_str)); pim_inet4_dump("<to?>", to.sin_addr, to_str, sizeof(to_str));
if (sent < 0) { if (sent < 0) {
zlog_warn("%s: sendto() failure to %s,%d: fd=%d len=%d: errno=%d: %s", zlog_warn("%s: sendto() failure to %s,%d: fd=%d len=%d: errno=%d: %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
to_str, ntohs(to.sin_port), ss->sock_fd, len, to_str, ntohs(to.sin_port), ss->sock_fd, len,
e, safe_strerror(e)); errno, safe_strerror(errno));
} }
else { else {
zlog_warn("%s: sendto() partial to %s,%d: fd=%d len=%d: sent=%d", zlog_warn("%s: sendto() partial to %s,%d: fd=%d len=%d: sent=%d",
@ -255,7 +252,7 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss)
&to, &tolen, &to, &tolen,
&ifindex); &ifindex);
if (len < 0) { if (len < 0) {
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str));
zlog_warn("%s: failure receiving ssmping for source %s on fd=%d: errno=%d: %s", zlog_warn("%s: failure receiving ssmping for source %s on fd=%d: errno=%d: %s",
__PRETTY_FUNCTION__, source_str, ss->sock_fd, errno, safe_strerror(errno)); __PRETTY_FUNCTION__, source_str, ss->sock_fd, errno, safe_strerror(errno));
@ -265,9 +262,9 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss)
ifp = if_lookup_by_index(ifindex); ifp = if_lookup_by_index(ifindex);
if (buf[0] != PIM_SSMPINGD_REQUEST) { if (buf[0] != PIM_SSMPINGD_REQUEST) {
char source_str[100]; char source_str[INET_ADDRSTRLEN];
char from_str[100]; char from_str[INET_ADDRSTRLEN];
char to_str[100]; char to_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str));
pim_inet4_dump("<from?>", from.sin_addr, from_str, sizeof(from_str)); pim_inet4_dump("<from?>", from.sin_addr, from_str, sizeof(from_str));
pim_inet4_dump("<to?>", to.sin_addr, to_str, sizeof(to_str)); pim_inet4_dump("<to?>", to.sin_addr, to_str, sizeof(to_str));
@ -283,9 +280,9 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss)
} }
if (PIM_DEBUG_SSMPINGD) { if (PIM_DEBUG_SSMPINGD) {
char source_str[100]; char source_str[INET_ADDRSTRLEN];
char from_str[100]; char from_str[INET_ADDRSTRLEN];
char to_str[100]; char to_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str));
pim_inet4_dump("<from?>", from.sin_addr, from_str, sizeof(from_str)); pim_inet4_dump("<from?>", from.sin_addr, from_str, sizeof(from_str));
pim_inet4_dump("<to?>", to.sin_addr, to_str, sizeof(to_str)); pim_inet4_dump("<to?>", to.sin_addr, to_str, sizeof(to_str));
@ -316,10 +313,7 @@ static int ssmpingd_sock_read(struct thread *t)
int sock_fd; int sock_fd;
int result; int result;
zassert(t);
ss = THREAD_ARG(t); ss = THREAD_ARG(t);
zassert(ss);
sock_fd = THREAD_FD(t); sock_fd = THREAD_FD(t);
zassert(sock_fd == ss->sock_fd); zassert(sock_fd == ss->sock_fd);
@ -357,18 +351,18 @@ static struct ssmpingd_sock *ssmpingd_new(struct in_addr source_addr)
sock_fd = ssmpingd_socket(source_addr, /* port: */ 4321, /* mTTL: */ 64); sock_fd = ssmpingd_socket(source_addr, /* port: */ 4321, /* mTTL: */ 64);
if (sock_fd < 0) { if (sock_fd < 0) {
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: ssmpingd_socket() failure for source %s", zlog_warn("%s: ssmpingd_socket() failure for source %s",
__PRETTY_FUNCTION__, source_str); __PRETTY_FUNCTION__, source_str);
return 0; return 0;
} }
ss = XMALLOC(MTYPE_PIM_SSMPINGD, sizeof(*ss)); ss = XCALLOC(MTYPE_PIM_SSMPINGD, sizeof(*ss));
if (!ss) { if (!ss) {
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_err("%s: XMALLOC(%zu) failure for ssmpingd source %s", zlog_err("%s: XCALLOC(%zu) failure for ssmpingd source %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
sizeof(*ss), source_str); sizeof(*ss), source_str);
close(sock_fd); close(sock_fd);
@ -399,7 +393,7 @@ int pim_ssmpingd_start(struct in_addr source_addr)
} }
{ {
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_info("%s: starting ssmpingd for source %s", zlog_info("%s: starting ssmpingd for source %s",
__PRETTY_FUNCTION__, source_str); __PRETTY_FUNCTION__, source_str);
@ -407,7 +401,7 @@ int pim_ssmpingd_start(struct in_addr source_addr)
ss = ssmpingd_new(source_addr); ss = ssmpingd_new(source_addr);
if (!ss) { if (!ss) {
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: ssmpingd_new() failure for source %s", zlog_warn("%s: ssmpingd_new() failure for source %s",
__PRETTY_FUNCTION__, source_str); __PRETTY_FUNCTION__, source_str);
@ -423,7 +417,7 @@ int pim_ssmpingd_stop(struct in_addr source_addr)
ss = ssmpingd_find(source_addr); ss = ssmpingd_find(source_addr);
if (!ss) { if (!ss) {
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: could not find ssmpingd for source %s", zlog_warn("%s: could not find ssmpingd for source %s",
__PRETTY_FUNCTION__, source_str); __PRETTY_FUNCTION__, source_str);
@ -431,7 +425,7 @@ int pim_ssmpingd_stop(struct in_addr source_addr)
} }
{ {
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_info("%s: stopping ssmpingd for source %s", zlog_info("%s: stopping ssmpingd for source %s",
__PRETTY_FUNCTION__, source_str); __PRETTY_FUNCTION__, source_str);

View File

@ -78,11 +78,11 @@ static struct static_route *static_route_new(unsigned int iif,
int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source) int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source)
{ {
struct listnode *node = 0; struct listnode *node = NULL;
struct static_route *s_route = 0; struct static_route *s_route = NULL;
struct static_route *original_s_route = 0; struct static_route *original_s_route = NULL;
struct pim_interface *pim_iif = iif ? iif->info : 0; struct pim_interface *pim_iif = iif ? iif->info : NULL;
struct pim_interface *pim_oif = oif ? oif->info : 0; struct pim_interface *pim_oif = oif ? oif->info : NULL;
ifindex_t iif_index = pim_iif ? pim_iif->mroute_vif_index : 0; ifindex_t iif_index = pim_iif ? pim_iif->mroute_vif_index : 0;
ifindex_t oif_index = pim_oif ? pim_oif->mroute_vif_index : 0; ifindex_t oif_index = pim_oif ? pim_oif->mroute_vif_index : 0;
@ -110,8 +110,8 @@ int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr
s_route->source.s_addr == source.s_addr) { s_route->source.s_addr == source.s_addr) {
if (s_route->iif == iif_index && if (s_route->iif == iif_index &&
s_route->oif_ttls[oif_index]) { s_route->oif_ttls[oif_index]) {
char gifaddr_str[100]; char gifaddr_str[INET_ADDRSTRLEN];
char sifaddr_str[100]; char sifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str)); pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str)); pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
zlog_warn("%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%s,source=%s)", zlog_warn("%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%s,source=%s)",
@ -174,10 +174,10 @@ int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr
listnode_add(qpim_static_route_list, s_route); listnode_add(qpim_static_route_list, s_route);
} }
if (pim_mroute_add(&s_route->c_oil)) if (pim_mroute_add(&s_route->c_oil, __PRETTY_FUNCTION__))
{ {
char gifaddr_str[100]; char gifaddr_str[INET_ADDRSTRLEN];
char sifaddr_str[100]; char sifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str)); pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str)); pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
zlog_warn("%s %s: Unable to add static route(iif=%d,oif=%d,group=%s,source=%s)", zlog_warn("%s %s: Unable to add static route(iif=%d,oif=%d,group=%s,source=%s)",
@ -209,8 +209,8 @@ int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr
} }
if (PIM_DEBUG_STATIC) { if (PIM_DEBUG_STATIC) {
char gifaddr_str[100]; char gifaddr_str[INET_ADDRSTRLEN];
char sifaddr_str[100]; char sifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str)); pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str)); pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
zlog_debug("%s: Static route added(iif=%d,oif=%d,group=%s,source=%s)", zlog_debug("%s: Static route added(iif=%d,oif=%d,group=%s,source=%s)",
@ -226,9 +226,9 @@ int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr
int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source) int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source)
{ {
struct listnode *node = 0; struct listnode *node = NULL;
struct listnode *nextnode = 0; struct listnode *nextnode = NULL;
struct static_route *s_route = 0; struct static_route *s_route = NULL;
struct pim_interface *pim_iif = iif ? iif->info : 0; struct pim_interface *pim_iif = iif ? iif->info : 0;
struct pim_interface *pim_oif = oif ? oif->info : 0; struct pim_interface *pim_oif = oif ? oif->info : 0;
ifindex_t iif_index = pim_iif ? pim_iif->mroute_vif_index : 0; ifindex_t iif_index = pim_iif ? pim_iif->mroute_vif_index : 0;
@ -253,23 +253,23 @@ int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr
/* If there are no more outputs then delete the whole route, otherwise set the route with the new outputs */ /* If there are no more outputs then delete the whole route, otherwise set the route with the new outputs */
if (s_route->c_oil.oil_ref_count <= 0 ? if (s_route->c_oil.oil_ref_count <= 0 ?
pim_mroute_del(&s_route->c_oil) : pim_mroute_add(&s_route->c_oil)) { pim_mroute_del(&s_route->c_oil, __PRETTY_FUNCTION__) : pim_mroute_add(&s_route->c_oil, __PRETTY_FUNCTION__)) {
char gifaddr_str[100]; char gifaddr_str[INET_ADDRSTRLEN];
char sifaddr_str[100]; char sifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str)); pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str)); pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
zlog_warn("%s %s: Unable to remove static route(iif=%d,oif=%d,group=%s,source=%s)", zlog_warn("%s %s: Unable to remove static route(iif=%d,oif=%d,group=%s,source=%s)",
__FILE__, __PRETTY_FUNCTION__, __FILE__, __PRETTY_FUNCTION__,
iif_index, iif_index,
oif_index, oif_index,
gifaddr_str, gifaddr_str,
sifaddr_str); sifaddr_str);
s_route->oif_ttls[oif_index] = 1; s_route->oif_ttls[oif_index] = 1;
s_route->c_oil.oil.mfcc_ttls[oif_index] = 1; s_route->c_oil.oil.mfcc_ttls[oif_index] = 1;
++s_route->c_oil.oil_ref_count; ++s_route->c_oil.oil_ref_count;
return -1; return -1;
} }
s_route->c_oil.oif_creation[oif_index] = 0; s_route->c_oil.oif_creation[oif_index] = 0;
@ -280,8 +280,8 @@ int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr
} }
if (PIM_DEBUG_STATIC) { if (PIM_DEBUG_STATIC) {
char gifaddr_str[100]; char gifaddr_str[INET_ADDRSTRLEN];
char sifaddr_str[100]; char sifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str)); pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str)); pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
zlog_debug("%s: Static route removed(iif=%d,oif=%d,group=%s,source=%s)", zlog_debug("%s: Static route removed(iif=%d,oif=%d,group=%s,source=%s)",
@ -297,8 +297,8 @@ int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr
} }
if (!node) { if (!node) {
char gifaddr_str[100]; char gifaddr_str[INET_ADDRSTRLEN];
char sifaddr_str[100]; char sifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str)); pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str)); pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
zlog_warn("%s %s: Unable to remove static route: Route does not exist(iif=%d,oif=%d,group=%s,source=%s)", zlog_warn("%s %s: Unable to remove static route: Route does not exist(iif=%d,oif=%d,group=%s,source=%s)",
@ -319,8 +319,8 @@ pim_static_write_mroute (struct vty *vty, struct interface *ifp)
struct listnode *node; struct listnode *node;
struct static_route *sroute; struct static_route *sroute;
int count = 0; int count = 0;
char sbuf[100]; char sbuf[INET_ADDRSTRLEN];
char gbuf[100]; char gbuf[INET_ADDRSTRLEN];
for (ALL_LIST_ELEMENTS_RO (qpim_static_route_list, node, sroute)) for (ALL_LIST_ELEMENTS_RO (qpim_static_route_list, node, sroute))
{ {

View File

@ -28,17 +28,62 @@
#include "pim_str.h" #include "pim_str.h"
void pim_inet4_dump(const char *onfail, struct in_addr addr, char *buf, int buf_size) void pim_addr_dump (const char *onfail, struct prefix *p, char *buf, int buf_size)
{ {
int save_errno = errno; int save_errno = errno;
if (!inet_ntop(AF_INET, &addr, buf, buf_size)) { if (!inet_ntop(p->family, &p->u.prefix, buf, buf_size)) {
int e = errno; zlog_warn("pim_addr_dump: inet_ntop(buf_size=%d): errno=%d: %s",
zlog_warn("pim_inet4_dump: inet_ntop(AF_INET,buf_size=%d): errno=%d: %s", buf_size, errno, safe_strerror(errno));
buf_size, e, safe_strerror(e));
if (onfail) if (onfail)
snprintf(buf, buf_size, "%s", onfail); snprintf(buf, buf_size, "%s", onfail);
} }
errno = save_errno; errno = save_errno;
} }
void pim_inet4_dump(const char *onfail, struct in_addr addr, char *buf, int buf_size)
{
int save_errno = errno;
if (addr.s_addr == INADDR_ANY)
strcpy(buf, "*");
else
{
if (!inet_ntop(AF_INET, &addr, buf, buf_size)) {
zlog_warn("pim_inet4_dump: inet_ntop(AF_INET,buf_size=%d): errno=%d: %s",
buf_size, errno, safe_strerror(errno));
if (onfail)
snprintf(buf, buf_size, "%s", onfail);
}
}
errno = save_errno;
}
char *
pim_str_sg_dump (const struct prefix_sg *sg)
{
char src_str[INET_ADDRSTRLEN];
char grp_str[INET_ADDRSTRLEN];
static char sg_str[PIM_SG_LEN];
pim_inet4_dump ("<src?>", sg->src, src_str, sizeof(src_str));
pim_inet4_dump ("<grp?>", sg->grp, grp_str, sizeof(grp_str));
snprintf (sg_str, PIM_SG_LEN, "(%s,%s)", src_str, grp_str);
return sg_str;
}
char *
pim_str_sg_set (const struct prefix_sg *sg, char *sg_str)
{
char src_str[INET_ADDRSTRLEN];
char grp_str[INET_ADDRSTRLEN];
pim_inet4_dump ("<src?>", sg->src, src_str, sizeof(src_str));
pim_inet4_dump ("<grp?>", sg->grp, grp_str, sizeof(grp_str));
snprintf (sg_str, PIM_SG_LEN, "(%s,%s)", src_str, grp_str);
return sg_str;
}

View File

@ -25,6 +25,20 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <prefix.h>
/*
* Longest possible length of a (S,G) string is 36 bytes
* 123.123.123.123 = 16 * 2
* (,) = 3
* NULL Character at end = 1
* (123.123.123.123,123,123,123,123)
*/
#define PIM_SG_LEN 36
void pim_addr_dump (const char *onfail, struct prefix *p, char *buf, int buf_size);
void pim_inet4_dump(const char *onfail, struct in_addr addr, char *buf, int buf_size); void pim_inet4_dump(const char *onfail, struct in_addr addr, char *buf, int buf_size);
char *pim_str_sg_dump (const struct prefix_sg *sg);
char *pim_str_sg_set (const struct prefix_sg *sg, char *sg_str);
#endif #endif

View File

@ -82,6 +82,25 @@ int64_t pim_time_monotonic_dsec()
return now_dsec; return now_dsec;
} }
int64_t
pim_time_monotonic_usec (void)
{
struct timeval now_tv;
int64_t now_dsec;
if (gettime_monotonic(&now_tv)) {
zlog_err("%s: gettime_monotonic() failure: errno=%d: %s",
__PRETTY_FUNCTION__,
errno, safe_strerror(errno));
return -1;
}
now_dsec = ((int64_t) now_tv.tv_sec) * 1000000 + ((int64_t) now_tv.tv_usec);
return now_dsec;
}
int pim_time_mmss(char *buf, int buf_size, long sec) int pim_time_mmss(char *buf, int buf_size, long sec)
{ {
long mm; long mm;

View File

@ -28,6 +28,7 @@
int64_t pim_time_monotonic_sec(void); int64_t pim_time_monotonic_sec(void);
int64_t pim_time_monotonic_dsec(void); int64_t pim_time_monotonic_dsec(void);
int64_t pim_time_monotonic_usec(void);
int pim_time_mmss(char *buf, int buf_size, long sec); int pim_time_mmss(char *buf, int buf_size, long sec);
void pim_time_timer_to_mmss(char *buf, int buf_size, struct thread *t); void pim_time_timer_to_mmss(char *buf, int buf_size, struct thread *t);
void pim_time_timer_to_hhmmss(char *buf, int buf_size, struct thread *t); void pim_time_timer_to_hhmmss(char *buf, int buf_size, struct thread *t);

View File

@ -95,8 +95,35 @@ uint8_t *pim_tlv_append_uint32(uint8_t *buf,
#define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr)) #define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
static int /*
pim_encode_unicast_address (uint8_t *buf, struct prefix *p) * An Encoded-Unicast address takes the following format:
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Addr Family | Encoding Type | Unicast Address
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
*
* Addr Family
* The PIM address family of the 'Unicast Address' field of this
* address.
*
* Values 0-127 are as assigned by the IANA for Internet Address * Families in [7]. Values 128-250 are reserved to be assigned by
* the IANA for PIM-specific Address Families. Values 251 though
* 255 are designated for private use. As there is no assignment
* authority for this space, collisions should be expected.
*
* Encoding Type
* The type of encoding used within a specific Address Family. The
* value '0' is reserved for this field and represents the native
* encoding of the Address Family.
*
* Unicast Address
* The unicast address as represented by the given Address Family
* and Encoding Type.
*/
int
pim_encode_addr_ucast (uint8_t *buf, struct prefix *p)
{ {
switch (p->family) switch (p->family)
{ {
@ -114,6 +141,79 @@ pim_encode_unicast_address (uint8_t *buf, struct prefix *p)
} }
} }
#define group_ipv4_encoding_len (4 + sizeof (struct in_addr))
/*
* Encoded-Group addresses take the following format:
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Addr Family | Encoding Type |B| Reserved |Z| Mask Len |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Group multicast Address
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
*
* Addr Family
* Described above.
*
* Encoding Type
* Described above.
*
* [B]idirectional PIM
* Indicates the group range should use Bidirectional PIM [13].
* For PIM-SM defined in this specification, this bit MUST be zero.
*
* Reserved
* Transmitted as zero. Ignored upon receipt.
*
* Admin Scope [Z]one
* indicates the group range is an admin scope zone. This is used
* in the Bootstrap Router Mechanism [11] only. For all other
* purposes, this bit is set to zero and ignored on receipt.
*
* Mask Len
* The Mask length field is 8 bits. The value is the number of
* contiguous one bits that are left justified and used as a mask;
* when combined with the group address, it describes a range of
* groups. It is less than or equal to the address length in bits
* for the given Address Family and Encoding Type. If the message
* is sent for a single group, then the Mask length must equal the
* address length in bits for the given Address Family and Encoding
* Type (e.g., 32 for IPv4 native encoding, 128 for IPv6 native
* encoding).
*
* Group multicast Address
* Contains the group address.
*/
int
pim_encode_addr_group (uint8_t *buf, afi_t afi, int bidir, int scope, struct in_addr group)
{
uint8_t flags = 0;
flags |= bidir << 8;
flags |= scope;
switch (afi)
{
case AFI_IP:
*(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV4;
++buf;
*(uint8_t *)buf = 0;
++buf;
*(uint8_t *)buf = flags;
++buf;
*(uint8_t *)buf = 32;
++buf;
memcpy (buf, &group, sizeof (struct in_addr));
return group_ipv4_encoding_len;
break;
default:
return 0;
break;
}
}
uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
const uint8_t *buf_pastend, const uint8_t *buf_pastend,
struct list *ifconnected) struct list *ifconnected)
@ -143,7 +243,7 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
if ((curr + ucast_ipv4_encoding_len) > buf_pastend) if ((curr + ucast_ipv4_encoding_len) > buf_pastend)
return 0; return 0;
l_encode = pim_encode_unicast_address (curr, p); l_encode = pim_encode_addr_ucast (curr, p);
curr += l_encode; curr += l_encode;
option_len += l_encode; option_len += l_encode;
} }
@ -173,7 +273,7 @@ static int check_tlv_length(const char *label, const char *tlv_name,
int correct_len, int option_len) int correct_len, int option_len)
{ {
if (option_len != correct_len) { if (option_len != correct_len) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s", zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s",
label, tlv_name, label, tlv_name,
@ -192,7 +292,7 @@ static void check_tlv_redefinition_uint16(const char *label, const char *tlv_nam
uint16_t new, uint16_t old) uint16_t new, uint16_t old)
{ {
if (PIM_OPTION_IS_SET(options, opt_mask)) { if (PIM_OPTION_IS_SET(options, opt_mask)) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
label, tlv_name, label, tlv_name,
@ -208,7 +308,7 @@ static void check_tlv_redefinition_uint32(const char *label, const char *tlv_nam
uint32_t new, uint32_t old) uint32_t new, uint32_t old)
{ {
if (PIM_OPTION_IS_SET(options, opt_mask)) { if (PIM_OPTION_IS_SET(options, opt_mask)) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
label, tlv_name, label, tlv_name,
@ -224,7 +324,7 @@ static void check_tlv_redefinition_uint32_hex(const char *label, const char *tlv
uint32_t new, uint32_t old) uint32_t new, uint32_t old)
{ {
if (PIM_OPTION_IS_SET(options, opt_mask)) { if (PIM_OPTION_IS_SET(options, opt_mask)) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s", zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s",
label, tlv_name, label, tlv_name,
@ -408,7 +508,7 @@ pim_parse_addr_ucast (struct prefix *p,
} }
int int
pim_parse_addr_group (struct prefix *p, pim_parse_addr_group (struct prefix_sg *sg,
const uint8_t *buf, const uint8_t *buf,
int buf_size) int buf_size)
{ {
@ -450,17 +550,15 @@ pim_parse_addr_group (struct prefix *p,
return -3; return -3;
} }
p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ memcpy(&sg->grp.s_addr, addr, sizeof(struct in_addr));
memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
p->prefixlen = mask_len;
addr += sizeof(struct in_addr); addr += sizeof(struct in_addr);
break; break;
default: default:
{ {
zlog_warn("%s: unknown group address encoding family=%d from", zlog_warn("%s: unknown group address encoding family=%d mask_len=%d from",
__PRETTY_FUNCTION__, family); __PRETTY_FUNCTION__, family, mask_len);
return -4; return -4;
} }
} }
@ -469,7 +567,7 @@ pim_parse_addr_group (struct prefix *p,
} }
int int
pim_parse_addr_source(struct prefix *p, pim_parse_addr_source(struct prefix_sg *sg,
uint8_t *flags, uint8_t *flags,
const uint8_t *buf, const uint8_t *buf,
int buf_size) int buf_size)
@ -513,9 +611,7 @@ pim_parse_addr_source(struct prefix *p,
return -3; return -3;
} }
p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ memcpy(&sg->src, addr, sizeof(struct in_addr));
memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
p->prefixlen = mask_len;
/* /*
RFC 4601: 4.9.1 Encoded Source and Group Address Formats RFC 4601: 4.9.1 Encoded Source and Group Address Formats
@ -527,9 +623,9 @@ pim_parse_addr_source(struct prefix *p,
and 128 for IPv6 native). A router SHOULD ignore any messages and 128 for IPv6 native). A router SHOULD ignore any messages
received with any other mask length. received with any other mask length.
*/ */
if (p->prefixlen != 32) { if (mask_len != 32) {
zlog_warn("%s: IPv4 bad source address mask: %d", zlog_warn("%s: IPv4 bad source address mask: %d",
__PRETTY_FUNCTION__, p->prefixlen); __PRETTY_FUNCTION__, mask_len);
return -4; return -4;
} }
@ -582,7 +678,7 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
*/ */
addr_offset = pim_parse_addr_ucast(&tmp, addr, pastend - addr); addr_offset = pim_parse_addr_ucast(&tmp, addr, pastend - addr);
if (addr_offset < 1) { if (addr_offset < 1) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -599,8 +695,8 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
switch (tmp.family) { switch (tmp.family) {
case AF_INET: case AF_INET:
{ {
char addr_str[100]; char addr_str[INET_ADDRSTRLEN];
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", tmp.u.prefix4, addr_str, sizeof(addr_str)); pim_inet4_dump("<addr?>", tmp.u.prefix4, addr_str, sizeof(addr_str));
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s", zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s",
@ -612,7 +708,7 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
break; break;
default: default:
{ {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s", zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -629,7 +725,7 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
*/ */
if (tmp.family == AF_INET) { if (tmp.family == AF_INET) {
if (tmp.u.prefix4.s_addr == src_addr.s_addr) { if (tmp.u.prefix4.s_addr == src_addr.s_addr) {
char src_str[100]; char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: ignoring primary address in secondary list from %s on %s", zlog_warn("%s: ignoring primary address in secondary list from %s on %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,

View File

@ -109,13 +109,16 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
uint16_t option_len, uint16_t option_len,
const uint8_t *tlv_curr); const uint8_t *tlv_curr);
int pim_encode_addr_ucast (uint8_t *buf, struct prefix *p);
int pim_encode_addr_group (uint8_t *buf, afi_t afi, int bidir, int scope, struct in_addr group);
int pim_parse_addr_ucast (struct prefix *p, int pim_parse_addr_ucast (struct prefix *p,
const uint8_t *buf, const uint8_t *buf,
int buf_size); int buf_size);
int pim_parse_addr_group (struct prefix *p, int pim_parse_addr_group (struct prefix_sg *sg,
const uint8_t *buf, const uint8_t *buf,
int buf_size); int buf_size);
int pim_parse_addr_source(struct prefix *p, int pim_parse_addr_source(struct prefix_sg *sg,
uint8_t *flags, uint8_t *flags,
const uint8_t *buf, const uint8_t *buf,
int buf_size); int buf_size);

File diff suppressed because it is too large Load Diff

View File

@ -22,52 +22,47 @@
#define PIM_UPSTREAM_H #define PIM_UPSTREAM_H
#include <zebra.h> #include <zebra.h>
#include <prefix.h>
#include <pimd/pim_rpf.h>
#define PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED (1 << 0) #define PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED (1 << 0)
#define PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED (2 << 0) #define PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED (1 << 1)
#define PIM_UPSTREAM_FLAG_MASK_FHR (1 << 2)
#define PIM_UPSTREAM_FLAG_MASK_SRC_IGMP (1 << 3)
#define PIM_UPSTREAM_FLAG_MASK_SRC_PIM (1 << 4)
#define PIM_UPSTREAM_FLAG_MASK_SRC_STREAM (1 << 5)
#define PIM_UPSTREAM_FLAG_MASK_SRC_MSDP (1 << 6)
#define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
#define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) #define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
#define PIM_UPSTREAM_FLAG_TEST_FHR(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_FHR)
#define PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
#define PIM_UPSTREAM_FLAG_TEST_SRC_PIM(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
#define PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
#define PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
#define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
#define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
#define PIM_UPSTREAM_FLAG_SET_FHR(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_FHR)
#define PIM_UPSTREAM_FLAG_SET_SRC_IGMP(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
#define PIM_UPSTREAM_FLAG_SET_SRC_PIM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
#define PIM_UPSTREAM_FLAG_SET_SRC_STREAM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
#define PIM_UPSTREAM_FLAG_SET_SRC_MSDP(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
#define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
#define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
#define PIM_UPSTREAM_FLAG_UNSET_FHR(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_FHR)
/* #define PIM_UPSTREAM_FLAG_UNSET_SRC_IGMP(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
RFC 4601: #define PIM_UPSTREAM_FLAG_UNSET_SRC_PIM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
#define PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
Metric Preference #define PIM_UPSTREAM_FLAG_UNSET_SRC_MSDP(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
Preference value assigned to the unicast routing protocol that
provided the route to the multicast source or Rendezvous-Point.
Metric
The unicast routing table metric associated with the route used to
reach the multicast source or Rendezvous-Point. The metric is in
units applicable to the unicast routing protocol used.
*/
struct pim_nexthop {
struct interface *interface; /* RPF_interface(S) */
struct in_addr mrib_nexthop_addr; /* MRIB.next_hop(S) */
uint32_t mrib_metric_preference; /* MRIB.pref(S) */
uint32_t mrib_route_metric; /* MRIB.metric(S) */
};
struct pim_rpf {
struct pim_nexthop source_nexthop;
struct in_addr rpf_addr; /* RPF'(S,G) */
};
enum pim_rpf_result {
PIM_RPF_OK = 0,
PIM_RPF_CHANGED,
PIM_RPF_FAILURE
};
enum pim_upstream_state { enum pim_upstream_state {
PIM_UPSTREAM_NOTJOINED, PIM_UPSTREAM_NOTJOINED,
PIM_UPSTREAM_JOINED PIM_UPSTREAM_JOINED,
PIM_UPSTREAM_JOIN_PENDING,
PIM_UPSTREAM_PRUNE,
}; };
enum pim_upstream_sptbit { enum pim_upstream_sptbit {
@ -83,11 +78,14 @@ enum pim_upstream_sptbit {
See RFC 4601: 4.5.7. Sending (S,G) Join/Prune Message See RFC 4601: 4.5.7. Sending (S,G) Join/Prune Message
*/ */
struct pim_upstream { struct pim_upstream {
struct pim_upstream *parent;
struct in_addr upstream_addr;/* Who we are talking to */ struct in_addr upstream_addr;/* Who we are talking to */
struct in_addr source_addr; /* (S,G) source key */ struct in_addr upstream_register; /*Who we received a register from*/
struct in_addr group_addr; /* (S,G) group key */ struct prefix_sg sg; /* (S,G) group key */
char sg_str[PIM_SG_LEN];
uint32_t flags; uint32_t flags;
struct channel_oil *channel_oil; struct channel_oil *channel_oil;
struct list *sources;
enum pim_upstream_state join_state; enum pim_upstream_state join_state;
enum pim_upstream_sptbit sptbit; enum pim_upstream_sptbit sptbit;
@ -98,6 +96,13 @@ struct pim_upstream {
struct thread *t_join_timer; struct thread *t_join_timer;
/*
* RST(S,G)
*/
struct thread *t_rs_timer;
#define PIM_REGISTER_SUPPRESSION_PERIOD (60)
#define PIM_REGISTER_PROBE_PERIOD (15)
/* /*
* KAT(S,G) * KAT(S,G)
*/ */
@ -105,17 +110,23 @@ struct pim_upstream {
#define PIM_KEEPALIVE_PERIOD (210) #define PIM_KEEPALIVE_PERIOD (210)
#define PIM_RP_KEEPALIVE_PERIOD ( 3 * qpim_register_suppress_time + qpim_register_probe_time ) #define PIM_RP_KEEPALIVE_PERIOD ( 3 * qpim_register_suppress_time + qpim_register_probe_time )
/* on the RP we restart a timer to indicate if registers are being rxed for
* SG. This is needed by MSDP to determine its local SA cache */
struct thread *t_msdp_reg_timer;
#define PIM_MSDP_REG_RXED_PERIOD (3 * (1.5 * qpim_register_suppress_time))
int64_t state_transition; /* Record current state uptime */ int64_t state_transition; /* Record current state uptime */
}; };
struct list *pim_upstream_list;
struct hash *pim_upstream_hash;
void pim_upstream_free(struct pim_upstream *up); void pim_upstream_free(struct pim_upstream *up);
void pim_upstream_delete(struct pim_upstream *up); struct pim_upstream *pim_upstream_find (struct prefix_sg *sg);
struct pim_upstream *pim_upstream_find(struct in_addr source_addr, struct pim_upstream *pim_upstream_add (struct prefix_sg *sg,
struct in_addr group_addr); struct interface *ifp, int flags,
struct pim_upstream *pim_upstream_add(struct in_addr source_addr, const char *name);
struct in_addr group_addr, void pim_upstream_del(struct pim_upstream *up, const char *name);
struct interface *ifp);
void pim_upstream_del(struct pim_upstream *up);
int pim_upstream_evaluate_join_desired(struct pim_upstream *up); int pim_upstream_evaluate_join_desired(struct pim_upstream *up);
void pim_upstream_update_join_desired(struct pim_upstream *up); void pim_upstream_update_join_desired(struct pim_upstream *up);
@ -136,7 +147,27 @@ void pim_upstream_update_my_assert_metric(struct pim_upstream *up);
void pim_upstream_keep_alive_timer_start (struct pim_upstream *up, uint32_t time); void pim_upstream_keep_alive_timer_start (struct pim_upstream *up, uint32_t time);
int pim_upstream_switch_to_spt_desired (struct in_addr source, struct in_addr group); int pim_upstream_switch_to_spt_desired (struct prefix_sg *sg);
#define SwitchToSptDesired(S,G) pim_upstream_switch_to_spt_desired ((S), (G)) #define SwitchToSptDesired(sg) pim_upstream_switch_to_spt_desired (sg)
int pim_upstream_is_sg_rpt (struct pim_upstream *up);
void pim_upstream_set_sptbit (struct pim_upstream *up, struct interface *incoming);
void pim_upstream_start_register_stop_timer (struct pim_upstream *up, int null_register);
void pim_upstream_send_join (struct pim_upstream *up);
void pim_upstream_switch (struct pim_upstream *up, enum pim_upstream_state new_state);
const char *pim_upstream_state2str (enum pim_upstream_state join_state);
int pim_upstream_inherited_olist_decide (struct pim_upstream *up);
int pim_upstream_inherited_olist (struct pim_upstream *up);
int pim_upstream_empty_inherited_olist (struct pim_upstream *up);
void pim_upstream_find_new_rpf (void);
void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up);
void pim_upstream_init (void);
void pim_upstream_terminate (void);
#endif /* PIM_UPSTREAM_H */ #endif /* PIM_UPSTREAM_H */

View File

@ -21,6 +21,7 @@
#include <zebra.h> #include <zebra.h>
#include "log.h" #include "log.h"
#include "prefix.h"
#include "pim_util.h" #include "pim_util.h"
@ -103,3 +104,43 @@ void pim_pkt_dump(const char *label, const uint8_t *buf, int size)
size); size);
zlog_hexdump(buf, size); zlog_hexdump(buf, size);
} }
int
pim_is_group_224_0_0_0_24 (struct in_addr group_addr)
{
static int first = 1;
static struct prefix group_224;
struct prefix group;
if (first)
{
str2prefix ("224.0.0.0/24", &group_224);
first = 0;
}
group.family = AF_INET;
group.u.prefix4 = group_addr;
group.prefixlen = 32;
return prefix_match (&group_224, &group);
}
int
pim_is_group_224_4 (struct in_addr group_addr)
{
static int first = 1;
static struct prefix group_all;
struct prefix group;
if (first)
{
str2prefix ("224.0.0.0/4", &group_all);
first = 0;
}
group.family = AF_INET;
group.u.prefix4 = group_addr;
group.prefixlen = 32;
return prefix_match (&group_all, &group);
}

View File

@ -32,4 +32,6 @@ uint16_t igmp_msg_decode8to16(uint8_t code);
void pim_pkt_dump(const char *label, const uint8_t *buf, int size); void pim_pkt_dump(const char *label, const uint8_t *buf, int size);
int pim_is_group_224_0_0_0_24 (struct in_addr group_addr);
int pim_is_group_224_4 (struct in_addr group_addr);
#endif /* PIM_UTIL_H */ #endif /* PIM_UTIL_H */

View File

@ -22,7 +22,10 @@
#include "if.h" #include "if.h"
#include "linklist.h" #include "linklist.h"
#include "prefix.h"
#include "vty.h"
#include "vrf.h" #include "vrf.h"
#include "plist.h"
#include "pimd.h" #include "pimd.h"
#include "pim_vty.h" #include "pim_vty.h"
@ -33,11 +36,26 @@
#include "pim_pim.h" #include "pim_pim.h"
#include "pim_oil.h" #include "pim_oil.h"
#include "pim_static.h" #include "pim_static.h"
#include "pim_rp.h"
#include "pim_msdp.h"
int pim_debug_config_write(struct vty *vty) int
pim_debug_config_write (struct vty *vty)
{ {
int writes = 0; int writes = 0;
if (PIM_DEBUG_MSDP_EVENTS) {
vty_out(vty, "debug msdp events%s", VTY_NEWLINE);
++writes;
}
if (PIM_DEBUG_MSDP_PACKETS) {
vty_out(vty, "debug msdp packets%s", VTY_NEWLINE);
++writes;
}
if (PIM_DEBUG_MSDP_INTERNAL) {
vty_out(vty, "debug msdp internal%s", VTY_NEWLINE);
++writes;
}
if (PIM_DEBUG_IGMP_EVENTS) { if (PIM_DEBUG_IGMP_EVENTS) {
vty_out(vty, "debug igmp events%s", VTY_NEWLINE); vty_out(vty, "debug igmp events%s", VTY_NEWLINE);
++writes; ++writes;
@ -50,12 +68,21 @@ int pim_debug_config_write(struct vty *vty)
vty_out(vty, "debug igmp trace%s", VTY_NEWLINE); vty_out(vty, "debug igmp trace%s", VTY_NEWLINE);
++writes; ++writes;
} }
if (PIM_DEBUG_IGMP_TRACE_DETAIL) {
vty_out(vty, "debug igmp trace detail%s", VTY_NEWLINE);
++writes;
}
if (PIM_DEBUG_MROUTE) { if (PIM_DEBUG_MROUTE) {
vty_out(vty, "debug mroute%s", VTY_NEWLINE); vty_out(vty, "debug mroute%s", VTY_NEWLINE);
++writes; ++writes;
} }
if (PIM_DEBUG_MROUTE_DETAIL) {
vty_out (vty, "debug mroute detail%s", VTY_NEWLINE);
++writes;
}
if (PIM_DEBUG_PIM_EVENTS) { if (PIM_DEBUG_PIM_EVENTS) {
vty_out(vty, "debug pim events%s", VTY_NEWLINE); vty_out(vty, "debug pim events%s", VTY_NEWLINE);
++writes; ++writes;
@ -72,10 +99,15 @@ int pim_debug_config_write(struct vty *vty)
vty_out(vty, "debug pim packet-dump receive%s", VTY_NEWLINE); vty_out(vty, "debug pim packet-dump receive%s", VTY_NEWLINE);
++writes; ++writes;
} }
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_TRACE) {
vty_out(vty, "debug pim trace%s", VTY_NEWLINE); vty_out(vty, "debug pim trace%s", VTY_NEWLINE);
++writes; ++writes;
} }
if (PIM_DEBUG_PIM_TRACE_DETAIL) {
vty_out(vty, "debug pim trace detail%s", VTY_NEWLINE);
++writes;
}
if (PIM_DEBUG_ZEBRA) { if (PIM_DEBUG_ZEBRA) {
vty_out(vty, "debug pim zebra%s", VTY_NEWLINE); vty_out(vty, "debug pim zebra%s", VTY_NEWLINE);
@ -87,22 +119,66 @@ int pim_debug_config_write(struct vty *vty)
++writes; ++writes;
} }
if (PIM_DEBUG_PIM_HELLO) {
vty_out (vty, "debug pim packets hello%s", VTY_NEWLINE);
++writes;
}
if (PIM_DEBUG_PIM_J_P) {
vty_out (vty, "debug pim packets joins%s", VTY_NEWLINE);
++writes;
}
if (PIM_DEBUG_PIM_REG) {
vty_out (vty, "debug pim packets register%s", VTY_NEWLINE);
++writes;
}
if (PIM_DEBUG_STATIC) {
vty_out (vty, "debug pim static%s", VTY_NEWLINE);
++writes;
}
return writes; return writes;
} }
int pim_global_config_write(struct vty *vty) int pim_global_config_write(struct vty *vty)
{ {
int writes = 0; int writes = 0;
char buffer[32];
writes += pim_msdp_config_write (vty);
if (PIM_MROUTE_IS_ENABLED) { if (PIM_MROUTE_IS_ENABLED) {
vty_out(vty, "ip multicast-routing%s", VTY_NEWLINE); vty_out(vty, "ip multicast-routing%s", VTY_NEWLINE);
++writes; ++writes;
} }
if (qpim_rp.rpf_addr.s_addr != INADDR_NONE) {
vty_out(vty, "ip pim rp %s%s", inet_ntop(AF_INET, &qpim_rp.rpf_addr, buffer, 32), VTY_NEWLINE); writes += pim_rp_config_write (vty);
++writes;
} if (qpim_register_suppress_time != PIM_REGISTER_SUPPRESSION_TIME_DEFAULT)
{
vty_out (vty, "ip pim register-suppress-time %d%s",
qpim_register_suppress_time, VTY_NEWLINE);
++writes;
}
if (qpim_t_periodic != PIM_DEFAULT_T_PERIODIC)
{
vty_out (vty, "ip pim join-prune-interval %d%s",
qpim_t_periodic, VTY_NEWLINE);
++writes;
}
if (qpim_keep_alive_time != PIM_KEEPALIVE_PERIOD)
{
vty_out (vty, "ip pim keep-alive-timer %d%s",
qpim_keep_alive_time, VTY_NEWLINE);
++writes;
}
if (qpim_packet_process != PIM_DEFAULT_PACKET_PROCESS)
{
vty_out (vty, "ip pim packets %d%s",
qpim_packet_process, VTY_NEWLINE);
++writes;
}
if (qpim_ssmpingd_list) { if (qpim_ssmpingd_list) {
struct listnode *node; struct listnode *node;
@ -110,7 +186,7 @@ int pim_global_config_write(struct vty *vty)
vty_out(vty, "!%s", VTY_NEWLINE); vty_out(vty, "!%s", VTY_NEWLINE);
++writes; ++writes;
for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) { for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) {
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str));
vty_out(vty, "ip ssmpingd %s%s", source_str, VTY_NEWLINE); vty_out(vty, "ip ssmpingd %s%s", source_str, VTY_NEWLINE);
++writes; ++writes;
@ -159,12 +235,30 @@ int pim_interface_config_write(struct vty *vty)
vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "%s", VTY_NEWLINE);
} }
/* update source */
if (PIM_INADDR_ISNOT_ANY(pim_ifp->update_source)) {
char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", pim_ifp->update_source, src_str,
sizeof(src_str));
vty_out(vty, " ip pim use-source %s%s", src_str, VTY_NEWLINE);
++writes;
}
/* IF ip igmp */ /* IF ip igmp */
if (PIM_IF_TEST_IGMP(pim_ifp->options)) { if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
vty_out(vty, " ip igmp%s", VTY_NEWLINE); vty_out(vty, " ip igmp%s", VTY_NEWLINE);
++writes; ++writes;
} }
/* ip igmp version */
if (pim_ifp->igmp_version != IGMP_DEFAULT_VERSION)
{
vty_out(vty, " ip igmp version %d%s",
pim_ifp->igmp_version,
VTY_NEWLINE);
++writes;
}
/* IF ip igmp query-interval */ /* IF ip igmp query-interval */
if (pim_ifp->igmp_default_query_interval != IGMP_GENERAL_QUERY_INTERVAL) if (pim_ifp->igmp_default_query_interval != IGMP_GENERAL_QUERY_INTERVAL)
{ {
@ -177,7 +271,7 @@ int pim_interface_config_write(struct vty *vty)
/* IF ip igmp query-max-response-time */ /* IF ip igmp query-max-response-time */
if (pim_ifp->igmp_query_max_response_time_dsec != IGMP_QUERY_MAX_RESPONSE_TIME_DSEC) if (pim_ifp->igmp_query_max_response_time_dsec != IGMP_QUERY_MAX_RESPONSE_TIME_DSEC)
{ {
vty_out(vty, " ip igmp query-max-response-time-dsec %d%s", vty_out(vty, " ip igpm query-max-response-time %d%s",
pim_ifp->igmp_query_max_response_time_dsec, pim_ifp->igmp_query_max_response_time_dsec,
VTY_NEWLINE); VTY_NEWLINE);
++writes; ++writes;
@ -188,10 +282,10 @@ int pim_interface_config_write(struct vty *vty)
struct listnode *node; struct listnode *node;
struct igmp_join *ij; struct igmp_join *ij;
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_join_list, node, ij)) { for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_join_list, node, ij)) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", ij->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<grp?>", ij->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", ij->source_addr, source_str, sizeof(source_str)); inet_ntop(AF_INET, &ij->source_addr, source_str, sizeof(source_str));
vty_out(vty, " ip igmp join %s %s%s", vty_out(vty, " ip igmp join %s %s%s",
group_str, source_str, group_str, source_str,
VTY_NEWLINE); VTY_NEWLINE);

View File

@ -28,6 +28,8 @@
#include "zclient.h" #include "zclient.h"
#include "stream.h" #include "stream.h"
#include "network.h" #include "network.h"
#include "vty.h"
#include "plist.h"
#include "pimd.h" #include "pimd.h"
#include "pim_pim.h" #include "pim_pim.h"
@ -171,6 +173,7 @@ static int pim_zebra_if_state_down(int command, struct zclient *zclient,
} }
if (!if_is_operative(ifp)) { if (!if_is_operative(ifp)) {
pim_ifchannel_delete_all(ifp);
/* /*
pim_if_addr_del_all() suffices for shutting down IGMP, pim_if_addr_del_all() suffices for shutting down IGMP,
but not for shutting down PIM but not for shutting down PIM
@ -186,6 +189,9 @@ static int pim_zebra_if_state_down(int command, struct zclient *zclient,
} }
} }
if (ifp->info)
pim_if_del_vif(ifp);
return 0; return 0;
} }
@ -220,7 +226,7 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
{ {
struct connected *c; struct connected *c;
struct prefix *p; struct prefix *p;
struct in_addr old = { .s_addr = 0 }; struct pim_interface *pim_ifp;
/* /*
zebra api notifies address adds/dels events by using the same call zebra api notifies address adds/dels events by using the same call
@ -234,10 +240,9 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
if (!c) if (!c)
return 0; return 0;
pim_ifp = c->ifp->info;
p = c->address; p = c->address;
if (p->family != AF_INET)
return 0;
if (PIM_DEBUG_ZEBRA) { if (PIM_DEBUG_ZEBRA) {
char buf[BUFSIZ]; char buf[BUFSIZ];
prefix2str(p, buf, BUFSIZ); prefix2str(p, buf, BUFSIZ);
@ -251,7 +256,25 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
#endif #endif
} }
pim_rp_check_rp (old, p->u.prefix4); if (p->family != AF_INET)
{
struct listnode *cnode;
struct connected *conn;
int v4addrs = 0;
for (ALL_LIST_ELEMENTS_RO (c->ifp->connected, cnode, conn))
{
if (conn->address->family == AF_INET)
v4addrs++;
}
if (!v4addrs && pim_ifp)
{
pim_ifp->primary_address = pim_find_primary_addr (c->ifp);
pim_if_addr_add_all (c->ifp);
pim_if_add_vif (c->ifp);
}
return 0;
}
if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) { if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
/* trying to add primary address */ /* trying to add primary address */
@ -262,20 +285,32 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
/* but we had a primary address already */ /* but we had a primary address already */
char buf[BUFSIZ]; char buf[BUFSIZ];
char old[100];
prefix2str(p, buf, BUFSIZ); prefix2str(p, buf, BUFSIZ);
pim_inet4_dump("<old?>", primary_addr, old, sizeof(old));
zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s", zlog_warn("%s: %s : forcing secondary flag on %s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
c->ifp->name, old, buf); c->ifp->name, buf);
} }
SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY); SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
} }
} }
pim_if_addr_add(c); pim_if_addr_add(c);
if (pim_ifp)
pim_rp_check_on_if_add(pim_ifp);
if (if_is_loopback (c->ifp))
{
struct listnode *ifnode;
struct interface *ifp;
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp))
{
if (!if_is_loopback (ifp) && if_is_operative (ifp))
pim_if_addr_add_all (ifp);
}
}
return 0; return 0;
} }
@ -285,7 +320,6 @@ static int pim_zebra_if_address_del(int command, struct zclient *client,
{ {
struct connected *c; struct connected *c;
struct prefix *p; struct prefix *p;
struct in_addr new = { .s_addr = 0 };
/* /*
zebra api notifies address adds/dels events by using the same call zebra api notifies address adds/dels events by using the same call
@ -316,8 +350,9 @@ static int pim_zebra_if_address_del(int command, struct zclient *client,
#endif #endif
} }
pim_rp_check_rp (p->u.prefix4, new);
pim_if_addr_del(c, 0); pim_if_addr_del(c, 0);
pim_rp_setup();
pim_i_am_rp_re_evaluate();
return 0; return 0;
} }
@ -328,18 +363,37 @@ static void scan_upstream_rpf_cache()
struct listnode *up_nextnode; struct listnode *up_nextnode;
struct pim_upstream *up; struct pim_upstream *up;
for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) { for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
struct in_addr old_rpf_addr; struct in_addr old_rpf_addr;
struct interface *old_interface;
enum pim_rpf_result rpf_result; enum pim_rpf_result rpf_result;
rpf_result = pim_rpf_update(up, &old_rpf_addr, NULL); old_interface = up->rpf.source_nexthop.interface;
rpf_result = pim_rpf_update(up, &old_rpf_addr);
if (rpf_result == PIM_RPF_FAILURE) if (rpf_result == PIM_RPF_FAILURE)
continue; continue;
if (rpf_result == PIM_RPF_CHANGED) { if (rpf_result == PIM_RPF_CHANGED) {
/*
* We have detected a case where we might need to rescan
* the inherited o_list so do it.
*/
if (up->channel_oil->oil_inherited_rescan)
{
pim_upstream_inherited_olist_decide (up);
up->channel_oil->oil_inherited_rescan = 0;
}
if (up->join_state == PIM_UPSTREAM_JOINED) { if (up->join_state == PIM_UPSTREAM_JOINED) {
/*
* If we come up real fast we can be here
* where the mroute has not been installed
* so install it.
*/
if (!up->channel_oil->installed)
pim_mroute_add (up->channel_oil, __PRETTY_FUNCTION__);
/* /*
RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
@ -356,17 +410,13 @@ static void scan_upstream_rpf_cache()
/* send Prune(S,G) to the old upstream neighbor */ /* send Prune(S,G) to the old upstream neighbor */
pim_joinprune_send(up->rpf.source_nexthop.interface, pim_joinprune_send(old_interface, old_rpf_addr,
old_rpf_addr, up, 0 /* prune */);
up->source_addr,
up->group_addr,
0 /* prune */);
/* send Join(S,G) to the current upstream neighbor */ /* send Join(S,G) to the current upstream neighbor */
pim_joinprune_send(up->rpf.source_nexthop.interface, pim_joinprune_send(up->rpf.source_nexthop.interface,
up->rpf.rpf_addr, up->rpf.rpf_addr.u.prefix4,
up->source_addr, up,
up->group_addr,
1 /* join */); 1 /* join */);
pim_upstream_join_timer_restart(up); pim_upstream_join_timer_restart(up);
@ -389,7 +439,7 @@ pim_scan_individual_oil (struct channel_oil *c_oil)
int input_iface_vif_index; int input_iface_vif_index;
int old_vif_index; int old_vif_index;
if (!pim_rp_set_upstream_addr (&vif_source, c_oil->oil.mfcc_origin)) if (!pim_rp_set_upstream_addr (&vif_source, c_oil->oil.mfcc_origin, c_oil->oil.mfcc_mcastgrp))
return; return;
input_iface_vif_index = fib_lookup_if_vif_index (vif_source); input_iface_vif_index = fib_lookup_if_vif_index (vif_source);
@ -397,20 +447,23 @@ pim_scan_individual_oil (struct channel_oil *c_oil)
{ {
if (PIM_DEBUG_ZEBRA) if (PIM_DEBUG_ZEBRA)
{ {
char source_str[100]; char source_str[INET_ADDRSTRLEN];
char group_str[100]; char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
zlog_debug("%s %s: could not find input interface(%d) for (S,G)=(%s,%s)", zlog_debug("%s %s: could not find input interface(%d) for (S,G)=(%s,%s)",
__FILE__, __PRETTY_FUNCTION__, c_oil->oil.mfcc_parent, __FILE__, __PRETTY_FUNCTION__, c_oil->oil.mfcc_parent,
source_str, group_str); source_str, group_str);
} }
pim_mroute_del (c_oil); pim_mroute_del (c_oil, __PRETTY_FUNCTION__);
return; return;
} }
if (input_iface_vif_index == c_oil->oil.mfcc_parent) if (input_iface_vif_index == c_oil->oil.mfcc_parent)
{ {
if (!c_oil->installed)
pim_mroute_add (c_oil, __PRETTY_FUNCTION__);
/* RPF unchanged */ /* RPF unchanged */
return; return;
} }
@ -419,15 +472,15 @@ pim_scan_individual_oil (struct channel_oil *c_oil)
{ {
struct interface *old_iif = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent); struct interface *old_iif = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent);
struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index); struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
char source_str[100]; char source_str[INET_ADDRSTRLEN];
char group_str[100]; char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d", zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
__FILE__, __PRETTY_FUNCTION__, __FILE__, __PRETTY_FUNCTION__,
source_str, group_str, source_str, group_str,
old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent, old_iif->name, c_oil->oil.mfcc_parent,
new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index); new_iif->name, input_iface_vif_index);
} }
/* new iif loops to existing oif ? */ /* new iif loops to existing oif ? */
@ -436,39 +489,41 @@ pim_scan_individual_oil (struct channel_oil *c_oil)
struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index); struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
if (PIM_DEBUG_ZEBRA) { if (PIM_DEBUG_ZEBRA) {
char source_str[100]; char source_str[INET_ADDRSTRLEN];
char group_str[100]; char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d", zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
__FILE__, __PRETTY_FUNCTION__, __FILE__, __PRETTY_FUNCTION__,
source_str, group_str, source_str, group_str,
new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index); new_iif->name, input_iface_vif_index);
} }
del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY); //del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY);
} }
/* update iif vif_index */ /* update iif vif_index */
old_vif_index = c_oil->oil.mfcc_parent; old_vif_index = c_oil->oil.mfcc_parent;
c_oil->oil.mfcc_parent = input_iface_vif_index; c_oil->oil.mfcc_parent = input_iface_vif_index;
zlog_debug ("FF");
/* update kernel multicast forwarding cache (MFC) */ /* update kernel multicast forwarding cache (MFC) */
if (pim_mroute_add(c_oil)) if (pim_mroute_add(c_oil, __PRETTY_FUNCTION__))
{ {
/* just log warning */ if (PIM_DEBUG_MROUTE)
struct interface *old_iif = pim_if_find_by_vif_index(old_vif_index); {
struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index); /* just log warning */
char source_str[100]; struct interface *old_iif = pim_if_find_by_vif_index(old_vif_index);
char group_str[100]; struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); char group_str[INET_ADDRSTRLEN];
zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d", pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
__FILE__, __PRETTY_FUNCTION__, pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
source_str, group_str, zlog_debug("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent, __FILE__, __PRETTY_FUNCTION__,
new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index); source_str, group_str,
old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
}
} }
} }
@ -481,13 +536,12 @@ void pim_scan_oil()
qpim_scan_oil_last = pim_time_monotonic_sec(); qpim_scan_oil_last = pim_time_monotonic_sec();
++qpim_scan_oil_events; ++qpim_scan_oil_events;
for (ALL_LIST_ELEMENTS(qpim_channel_oil_list, node, nextnode, c_oil)) for (ALL_LIST_ELEMENTS(pim_channel_oil_list, node, nextnode, c_oil))
pim_scan_individual_oil (c_oil); pim_scan_individual_oil (c_oil);
} }
static int on_rpf_cache_refresh(struct thread *t) static int on_rpf_cache_refresh(struct thread *t)
{ {
zassert(t);
zassert(qpim_rpf_cache_refresher); zassert(qpim_rpf_cache_refresher);
qpim_rpf_cache_refresher = 0; qpim_rpf_cache_refresher = 0;
@ -501,13 +555,16 @@ static int on_rpf_cache_refresh(struct thread *t)
qpim_rpf_cache_refresh_last = pim_time_monotonic_sec(); qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
++qpim_rpf_cache_refresh_events; ++qpim_rpf_cache_refresh_events;
pim_rp_setup ();
return 0; return 0;
} }
static void sched_rpf_cache_refresh() void sched_rpf_cache_refresh(void)
{ {
++qpim_rpf_cache_refresh_requests; ++qpim_rpf_cache_refresh_requests;
pim_rpf_set_refresh_time ();
if (qpim_rpf_cache_refresher) { if (qpim_rpf_cache_refresher) {
/* Refresh timer is already running */ /* Refresh timer is already running */
return; return;
@ -575,17 +632,6 @@ static int redist_read_ipv4_route(int command, struct zclient *zclient,
CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : ""); CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
} }
if (length < min_len) {
zlog_warn("%s %s: short buffer: length=%d min_len=%d flags=%s%s%s%s",
__FILE__, __PRETTY_FUNCTION__,
length, min_len,
CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
return -1;
}
/* IPv4 prefix. */ /* IPv4 prefix. */
stream_get(&p.prefix, s, PSIZE(p.prefixlen)); stream_get(&p.prefix, s, PSIZE(p.prefixlen));
@ -654,6 +700,7 @@ static int redist_read_ipv4_route(int command, struct zclient *zclient,
sched_rpf_cache_refresh(); sched_rpf_cache_refresh();
pim_rp_setup ();
return 0; return 0;
} }
@ -662,6 +709,7 @@ pim_zebra_connected (struct zclient *zclient)
{ {
zclient_send_reg_requests (zclient, VRF_DEFAULT); zclient_send_reg_requests (zclient, VRF_DEFAULT);
} }
void pim_zebra_init(char *zebra_sock_path) void pim_zebra_init(char *zebra_sock_path)
{ {
int i; int i;
@ -719,9 +767,7 @@ void pim_zebra_init(char *zebra_sock_path)
__PRETTY_FUNCTION__); __PRETTY_FUNCTION__);
} }
zassert(!qpim_zclient_lookup); zclient_lookup_new();
qpim_zclient_lookup = zclient_lookup_new();
zassert(qpim_zclient_lookup);
} }
void igmp_anysource_forward_start(struct igmp_group *group) void igmp_anysource_forward_start(struct igmp_group *group)
@ -754,36 +800,42 @@ void igmp_anysource_forward_stop(struct igmp_group *group)
static int fib_lookup_if_vif_index(struct in_addr addr) static int fib_lookup_if_vif_index(struct in_addr addr)
{ {
struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE]; struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
int num_ifindex; int num_ifindex;
int vif_index; int vif_index;
ifindex_t first_ifindex; ifindex_t first_ifindex;
num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab, num_ifindex = zclient_lookup_nexthop(nexthop_tab,
PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr, MULTIPATH_NUM, addr,
PIM_NEXTHOP_LOOKUP_MAX); PIM_NEXTHOP_LOOKUP_MAX);
if (num_ifindex < 1) { if (num_ifindex < 1) {
char addr_str[100]; if (PIM_DEBUG_ZEBRA)
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); {
zlog_warn("%s %s: could not find nexthop ifindex for address %s", char addr_str[INET_ADDRSTRLEN];
__FILE__, __PRETTY_FUNCTION__, pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
addr_str); zlog_debug("%s %s: could not find nexthop ifindex for address %s",
__FILE__, __PRETTY_FUNCTION__,
addr_str);
}
return -1; return -1;
} }
first_ifindex = nexthop_tab[0].ifindex; first_ifindex = nexthop_tab[0].ifindex;
if (num_ifindex > 1) { if (num_ifindex > 1) {
char addr_str[100]; if (PIM_DEBUG_ZEBRA)
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); {
zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)", char addr_str[INET_ADDRSTRLEN];
__FILE__, __PRETTY_FUNCTION__, pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
num_ifindex, addr_str, first_ifindex); zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
__FILE__, __PRETTY_FUNCTION__,
num_ifindex, addr_str, first_ifindex);
}
/* debug warning only, do not return */ /* debug warning only, do not return */
} }
if (PIM_DEBUG_ZEBRA) { if (PIM_DEBUG_ZEBRA) {
char addr_str[100]; char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s", zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
__FILE__, __PRETTY_FUNCTION__, __FILE__, __PRETTY_FUNCTION__,
@ -793,31 +845,17 @@ static int fib_lookup_if_vif_index(struct in_addr addr)
vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex); vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
if (vif_index < 0) { if (vif_index < 0) {
char addr_str[100]; if (PIM_DEBUG_ZEBRA)
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); {
zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s", char addr_str[INET_ADDRSTRLEN];
__FILE__, __PRETTY_FUNCTION__, pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
vif_index, addr_str); zlog_debug("%s %s: low vif_index=%d < 1 nexthop for address %s",
__FILE__, __PRETTY_FUNCTION__,
vif_index, addr_str);
}
return -2; return -2;
} }
zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
if (vif_index > qpim_mroute_oif_highest_vif_index) {
char addr_str[100];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
__FILE__, __PRETTY_FUNCTION__,
vif_index, qpim_mroute_oif_highest_vif_index, addr_str);
zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
__FILE__, __PRETTY_FUNCTION__,
ifindex2ifname(vif_index),
vif_index);
return -3;
}
return vif_index; return vif_index;
} }
@ -828,17 +866,11 @@ static int del_oif(struct channel_oil *channel_oil,
struct pim_interface *pim_ifp; struct pim_interface *pim_ifp;
int old_ttl; int old_ttl;
zassert(channel_oil);
pim_ifp = oif->info; pim_ifp = oif->info;
zassert(pim_ifp->mroute_vif_index >= 1);
zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
if (PIM_DEBUG_MROUTE) { if (PIM_DEBUG_MROUTE) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d", zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
@ -850,15 +882,18 @@ static int del_oif(struct channel_oil *channel_oil,
/* Prevent single protocol from unsubscribing same interface from /* Prevent single protocol from unsubscribing same interface from
channel (S,G) multiple times */ channel (S,G) multiple times */
if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) { if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
char group_str[100]; if (PIM_DEBUG_MROUTE)
char source_str[100]; {
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); char source_str[INET_ADDRSTRLEN];
zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)", pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
__FILE__, __PRETTY_FUNCTION__, pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
proto_mask, oif->name, pim_ifp->mroute_vif_index, zlog_debug("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index], __FILE__, __PRETTY_FUNCTION__,
source_str, group_str); proto_mask, oif->name, pim_ifp->mroute_vif_index,
channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
source_str, group_str);
}
return -2; return -2;
} }
@ -873,15 +908,18 @@ static int del_oif(struct channel_oil *channel_oil,
/* Check the OIF keeps existing before returning, and only log /* Check the OIF keeps existing before returning, and only log
warning otherwise */ warning otherwise */
if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) { if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
char group_str[100]; if (PIM_DEBUG_MROUTE)
char source_str[100]; {
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); char source_str[INET_ADDRSTRLEN];
zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)", pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
__FILE__, __PRETTY_FUNCTION__, pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
proto_mask, oif->name, pim_ifp->mroute_vif_index, zlog_debug("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index], __FILE__, __PRETTY_FUNCTION__,
source_str, group_str); proto_mask, oif->name, pim_ifp->mroute_vif_index,
channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
source_str, group_str);
}
} }
return 0; return 0;
@ -890,22 +928,25 @@ static int del_oif(struct channel_oil *channel_oil,
old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index]; old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
if (old_ttl < 1) { if (old_ttl < 1) {
char group_str[100]; if (PIM_DEBUG_MROUTE)
char source_str[100]; {
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); char source_str[INET_ADDRSTRLEN];
zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)", pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
__FILE__, __PRETTY_FUNCTION__, pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
oif->name, pim_ifp->mroute_vif_index, zlog_debug("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
source_str, group_str); __FILE__, __PRETTY_FUNCTION__,
oif->name, pim_ifp->mroute_vif_index,
source_str, group_str);
}
return -3; return -3;
} }
channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0; channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
if (pim_mroute_add(channel_oil)) { if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)", zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
@ -920,21 +961,24 @@ static int del_oif(struct channel_oil *channel_oil,
--channel_oil->oil_size; --channel_oil->oil_size;
if (channel_oil->oil_size < 1) { if (channel_oil->oil_size < 1) {
if (pim_mroute_del(channel_oil)) { if (pim_mroute_del(channel_oil, __PRETTY_FUNCTION__)) {
/* just log a warning in case of failure */ if (PIM_DEBUG_MROUTE)
char group_str[100]; {
char source_str[100]; /* just log a warning in case of failure */
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); char source_str[INET_ADDRSTRLEN];
zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)", pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
__FILE__, __PRETTY_FUNCTION__, pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
source_str, group_str); zlog_debug("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
__FILE__, __PRETTY_FUNCTION__,
source_str, group_str);
}
} }
} }
if (PIM_DEBUG_MROUTE) { if (PIM_DEBUG_MROUTE) {
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char source_str[100]; char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE", zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
@ -949,16 +993,17 @@ static int del_oif(struct channel_oil *channel_oil,
void igmp_source_forward_start(struct igmp_source *source) void igmp_source_forward_start(struct igmp_source *source)
{ {
struct igmp_group *group; struct igmp_group *group;
struct prefix_sg sg;
int result; int result;
memset (&sg, 0, sizeof (struct prefix_sg));
sg.src = source->source_addr;
sg.grp = source->source_group->group_addr;
if (PIM_DEBUG_IGMP_TRACE) { if (PIM_DEBUG_IGMP_TRACE) {
char source_str[100]; zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
char group_str[100];
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
source_str, group_str, pim_str_sg_dump (&sg),
source->source_group->group_igmp_sock->fd, source->source_group->group_igmp_sock->fd,
source->source_group->group_igmp_sock->interface->name, source->source_group->group_igmp_sock->interface->name,
IGMP_SOURCE_TEST_FORWARDING(source->source_flags)); IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
@ -976,16 +1021,19 @@ void igmp_source_forward_start(struct igmp_source *source)
struct in_addr vif_source; struct in_addr vif_source;
struct pim_interface *pim_oif; struct pim_interface *pim_oif;
if (!pim_rp_set_upstream_addr (&vif_source, source->source_addr)) if (!pim_rp_set_upstream_addr (&vif_source, source->source_addr, sg.grp))
return; return;
int input_iface_vif_index = fib_lookup_if_vif_index(vif_source); int input_iface_vif_index = fib_lookup_if_vif_index(vif_source);
if (input_iface_vif_index < 1) { if (input_iface_vif_index < 1) {
char source_str[100]; if (PIM_DEBUG_IGMP_TRACE)
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str)); {
zlog_warn("%s %s: could not find input interface for source %s", char source_str[INET_ADDRSTRLEN];
__FILE__, __PRETTY_FUNCTION__, pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
source_str); zlog_debug("%s %s: could not find input interface for source %s",
__FILE__, __PRETTY_FUNCTION__,
source_str);
}
return; return;
} }
@ -996,28 +1044,21 @@ void igmp_source_forward_start(struct igmp_source *source)
*/ */
pim_oif = source->source_group->group_igmp_sock->interface->info; pim_oif = source->source_group->group_igmp_sock->interface->info;
if (!pim_oif) { if (!pim_oif) {
zlog_warn("%s: multicast not enabled on oif=%s ?", if (PIM_DEBUG_IGMP_TRACE)
__PRETTY_FUNCTION__, {
source->source_group->group_igmp_sock->interface->name); zlog_debug("%s: multicast not enabled on oif=%s ?",
return; __PRETTY_FUNCTION__,
} source->source_group->group_igmp_sock->interface->name);
if (pim_oif->mroute_vif_index < 1) { }
zlog_warn("%s %s: oif=%s vif_index=%d < 1",
__FILE__, __PRETTY_FUNCTION__,
source->source_group->group_igmp_sock->interface->name,
pim_oif->mroute_vif_index);
return; return;
} }
if (input_iface_vif_index == pim_oif->mroute_vif_index) { if (input_iface_vif_index == pim_oif->mroute_vif_index) {
/* ignore request for looped MFC entry */ /* ignore request for looped MFC entry */
if (PIM_DEBUG_IGMP_TRACE) { if (PIM_DEBUG_IGMP_TRACE) {
char source_str[100]; zlog_debug("%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
char group_str[100];
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
source_str, group_str, pim_str_sg_dump (&sg),
source->source_group->group_igmp_sock->fd, source->source_group->group_igmp_sock->fd,
source->source_group->group_igmp_sock->interface->name, source->source_group->group_igmp_sock->interface->name,
input_iface_vif_index); input_iface_vif_index);
@ -1025,17 +1066,15 @@ void igmp_source_forward_start(struct igmp_source *source)
return; return;
} }
source->source_channel_oil = pim_channel_oil_add(group->group_addr, source->source_channel_oil = pim_channel_oil_add(&sg,
source->source_addr,
input_iface_vif_index); input_iface_vif_index);
if (!source->source_channel_oil) { if (!source->source_channel_oil) {
char group_str[100]; if (PIM_DEBUG_IGMP_TRACE)
char source_str[100]; {
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str)); zlog_debug("%s %s: could not create OIL for channel (S,G)=%s",
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str)); __FILE__, __PRETTY_FUNCTION__,
zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)", pim_str_sg_dump (&sg));
__FILE__, __PRETTY_FUNCTION__, }
source_str, group_str);
return; return;
} }
} }
@ -1044,8 +1083,11 @@ void igmp_source_forward_start(struct igmp_source *source)
group->group_igmp_sock->interface, group->group_igmp_sock->interface,
PIM_OIF_FLAG_PROTO_IGMP); PIM_OIF_FLAG_PROTO_IGMP);
if (result) { if (result) {
zlog_warn("%s: add_oif() failed with return=%d", if (PIM_DEBUG_MROUTE)
__func__, result); {
zlog_warn("%s: add_oif() failed with return=%d",
__func__, result);
}
return; return;
} }
@ -1053,8 +1095,7 @@ void igmp_source_forward_start(struct igmp_source *source)
Feed IGMPv3-gathered local membership information into PIM Feed IGMPv3-gathered local membership information into PIM
per-interface (S,G) state. per-interface (S,G) state.
*/ */
pim_ifchannel_local_membership_add(group->group_igmp_sock->interface, pim_ifchannel_local_membership_add(group->group_igmp_sock->interface, &sg);
source->source_addr, group->group_addr);
IGMP_SOURCE_DO_FORWARDING(source->source_flags); IGMP_SOURCE_DO_FORWARDING(source->source_flags);
} }
@ -1066,16 +1107,17 @@ void igmp_source_forward_start(struct igmp_source *source)
void igmp_source_forward_stop(struct igmp_source *source) void igmp_source_forward_stop(struct igmp_source *source)
{ {
struct igmp_group *group; struct igmp_group *group;
struct prefix_sg sg;
int result; int result;
memset (&sg, 0, sizeof (struct prefix_sg));
sg.src = source->source_addr;
sg.grp = source->source_group->group_addr;
if (PIM_DEBUG_IGMP_TRACE) { if (PIM_DEBUG_IGMP_TRACE) {
char source_str[100]; zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
char group_str[100];
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
source_str, group_str, pim_str_sg_dump (&sg),
source->source_group->group_igmp_sock->fd, source->source_group->group_igmp_sock->fd,
source->source_group->group_igmp_sock->interface->name, source->source_group->group_igmp_sock->interface->name,
IGMP_SOURCE_TEST_FORWARDING(source->source_flags)); IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
@ -1104,8 +1146,9 @@ void igmp_source_forward_stop(struct igmp_source *source)
group->group_igmp_sock->interface, group->group_igmp_sock->interface,
PIM_OIF_FLAG_PROTO_IGMP); PIM_OIF_FLAG_PROTO_IGMP);
if (result) { if (result) {
zlog_warn("%s: del_oif() failed with return=%d", if (PIM_DEBUG_IGMP_TRACE)
__func__, result); zlog_debug("%s: del_oif() failed with return=%d",
__func__, result);
return; return;
} }
@ -1114,7 +1157,7 @@ void igmp_source_forward_stop(struct igmp_source *source)
per-interface (S,G) state. per-interface (S,G) state.
*/ */
pim_ifchannel_local_membership_del(group->group_igmp_sock->interface, pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
source->source_addr, group->group_addr); &sg);
IGMP_SOURCE_DONT_FORWARDING(source->source_flags); IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
} }
@ -1124,12 +1167,12 @@ void pim_forward_start(struct pim_ifchannel *ch)
struct pim_upstream *up = ch->upstream; struct pim_upstream *up = ch->upstream;
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_TRACE) {
char source_str[100]; char source_str[INET_ADDRSTRLEN];
char group_str[100]; char group_str[INET_ADDRSTRLEN];
char upstream_str[100]; char upstream_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("<source?>", ch->sg.src, source_str, sizeof(source_str));
pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<group?>", ch->sg.grp, group_str, sizeof(group_str));
pim_inet4_dump("<upstream?>", up->upstream_addr, upstream_str, sizeof(upstream_str)); pim_inet4_dump("<upstream?>", up->upstream_addr, upstream_str, sizeof(upstream_str));
zlog_debug("%s: (S,G)=(%s,%s) oif=%s(%s)", zlog_debug("%s: (S,G)=(%s,%s) oif=%s(%s)",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -1139,24 +1182,24 @@ void pim_forward_start(struct pim_ifchannel *ch)
if (!up->channel_oil) { if (!up->channel_oil) {
int input_iface_vif_index = fib_lookup_if_vif_index(up->upstream_addr); int input_iface_vif_index = fib_lookup_if_vif_index(up->upstream_addr);
if (input_iface_vif_index < 1) { if (input_iface_vif_index < 1) {
char source_str[100]; if (PIM_DEBUG_PIM_TRACE)
pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str)); {
zlog_warn("%s %s: could not find input interface for source %s", char source_str[INET_ADDRSTRLEN];
__FILE__, __PRETTY_FUNCTION__, pim_inet4_dump("<source?>", up->sg.src, source_str, sizeof(source_str));
source_str); zlog_debug("%s %s: could not find input interface for source %s",
__FILE__, __PRETTY_FUNCTION__,
source_str);
}
return; return;
} }
up->channel_oil = pim_channel_oil_add(up->group_addr, up->source_addr, up->channel_oil = pim_channel_oil_add(&up->sg,
input_iface_vif_index); input_iface_vif_index);
if (!up->channel_oil) { if (!up->channel_oil) {
char group_str[100]; if (PIM_DEBUG_PIM_TRACE)
char source_str[100]; zlog_debug("%s %s: could not create OIL for channel (S,G)=%s",
pim_inet4_dump("<group?>", up->group_addr, group_str, sizeof(group_str)); __FILE__, __PRETTY_FUNCTION__,
pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str)); up->sg_str);
zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
__FILE__, __PRETTY_FUNCTION__,
source_str, group_str);
return; return;
} }
} }
@ -1171,23 +1214,16 @@ void pim_forward_stop(struct pim_ifchannel *ch)
struct pim_upstream *up = ch->upstream; struct pim_upstream *up = ch->upstream;
if (PIM_DEBUG_PIM_TRACE) { if (PIM_DEBUG_PIM_TRACE) {
char source_str[100]; zlog_debug("%s: (S,G)=%s oif=%s",
char group_str[100];
pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
source_str, group_str, ch->interface->name); ch->sg_str, ch->interface->name);
} }
if (!up->channel_oil) { if (!up->channel_oil) {
char source_str[100]; if (PIM_DEBUG_PIM_TRACE)
char group_str[100]; zlog_debug("%s: (S,G)=%s oif=%s missing channel OIL",
pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str)); __PRETTY_FUNCTION__,
pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str)); ch->sg_str, ch->interface->name);
zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
__PRETTY_FUNCTION__,
source_str, group_str, ch->interface->name);
return; return;
} }

View File

@ -38,4 +38,5 @@ void igmp_source_forward_stop(struct igmp_source *source);
void pim_forward_start(struct pim_ifchannel *ch); void pim_forward_start(struct pim_ifchannel *ch);
void pim_forward_stop(struct pim_ifchannel *ch); void pim_forward_stop(struct pim_ifchannel *ch);
void sched_rpf_cache_refresh(void);
#endif /* PIM_ZEBRA_H */ #endif /* PIM_ZEBRA_H */

View File

@ -27,13 +27,17 @@
#include "stream.h" #include "stream.h"
#include "network.h" #include "network.h"
#include "thread.h" #include "thread.h"
#include "prefix.h"
#include "vty.h"
#include "pimd.h" #include "pimd.h"
#include "pim_iface.h"
#include "pim_pim.h" #include "pim_pim.h"
#include "pim_str.h" #include "pim_str.h"
#include "pim_oil.h"
#include "pim_zlookup.h" #include "pim_zlookup.h"
extern int zclient_debug; static struct zclient *zlookup = NULL;
static void zclient_lookup_sched(struct zclient *zlookup, int delay); static void zclient_lookup_sched(struct zclient *zlookup, int delay);
@ -116,15 +120,14 @@ static void zclient_lookup_failed(struct zclient *zlookup)
zclient_lookup_reconnect(zlookup); zclient_lookup_reconnect(zlookup);
} }
struct zclient *zclient_lookup_new() void
zclient_lookup_new (void)
{ {
struct zclient *zlookup;
zlookup = zclient_new (master); zlookup = zclient_new (master);
if (!zlookup) { if (!zlookup) {
zlog_err("%s: zclient_new() failure", zlog_err("%s: zclient_new() failure",
__PRETTY_FUNCTION__); __PRETTY_FUNCTION__);
return 0; return;
} }
zlookup->sock = -1; zlookup->sock = -1;
@ -137,7 +140,6 @@ struct zclient *zclient_lookup_new()
zlog_notice("%s: zclient lookup socket initialized", zlog_notice("%s: zclient lookup socket initialized",
__PRETTY_FUNCTION__); __PRETTY_FUNCTION__);
return zlookup;
} }
static int zclient_read_nexthop(struct zclient *zlookup, static int zclient_read_nexthop(struct zclient *zlookup,
@ -159,8 +161,8 @@ static int zclient_read_nexthop(struct zclient *zlookup,
int nexthop_num; int nexthop_num;
int i, err; int i, err;
if (PIM_DEBUG_ZEBRA) { if (PIM_DEBUG_PIM_TRACE_DETAIL) {
char addr_str[100]; char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s: addr=%s", zlog_debug("%s: addr=%s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -192,8 +194,8 @@ static int zclient_read_nexthop(struct zclient *zlookup,
raddr.s_addr = stream_get_ipv4(s); raddr.s_addr = stream_get_ipv4(s);
if (raddr.s_addr != addr.s_addr) { if (raddr.s_addr != addr.s_addr) {
char addr_str[100]; char addr_str[INET_ADDRSTRLEN];
char raddr_str[100]; char raddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
pim_inet4_dump("<raddr?>", raddr, raddr_str, sizeof(raddr_str)); pim_inet4_dump("<raddr?>", raddr, raddr_str, sizeof(raddr_str));
zlog_warn("%s: address mismatch: addr=%s raddr=%s", zlog_warn("%s: address mismatch: addr=%s raddr=%s",
@ -212,77 +214,52 @@ static int zclient_read_nexthop(struct zclient *zlookup,
return -6; return -6;
} }
length -= MIN_LEN;
for (i = 0; i < nexthop_num; ++i) { for (i = 0; i < nexthop_num; ++i) {
enum nexthop_types_t nexthop_type; enum nexthop_types_t nexthop_type;
struct pim_neighbor *nbr;
if (length < 1) {
zlog_err("%s: socket %d empty input expecting nexthop_type: len=%d",
__func__, zlookup->sock, length);
return -7;
}
nexthop_type = stream_getc(s); nexthop_type = stream_getc(s);
--length; if (num_ifindex >= tab_size) {
char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_warn("%s %s: found too many nexthop ifindexes (%d > %d) for address %s",
__FILE__, __PRETTY_FUNCTION__,
(num_ifindex + 1), tab_size, addr_str);
return num_ifindex;
}
switch (nexthop_type) { switch (nexthop_type) {
case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFINDEX:
case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4_IFINDEX:
if (num_ifindex >= tab_size) { case NEXTHOP_TYPE_IPV4:
char addr_str[100]; nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET;
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); if (nexthop_type == NEXTHOP_TYPE_IPV4_IFINDEX ||
zlog_warn("%s %s: found too many nexthop ifindexes (%d > %d) for address %s", nexthop_type == NEXTHOP_TYPE_IPV4) {
__FILE__, __PRETTY_FUNCTION__, nexthop_tab[num_ifindex].nexthop_addr.u.prefix4.s_addr = stream_get_ipv4(s);
(num_ifindex + 1), tab_size, addr_str);
return num_ifindex;
}
if (nexthop_type == NEXTHOP_TYPE_IPV4_IFINDEX) {
if (length < 4) {
zlog_err("%s: socket %d short input expecting nexthop IPv4-addr: len=%d",
__func__, zlookup->sock, length);
return -8;
}
nexthop_tab[num_ifindex].nexthop_addr.s_addr = stream_get_ipv4(s);
length -= 4;
} }
else { else {
nexthop_tab[num_ifindex].nexthop_addr.s_addr = PIM_NET_INADDR_ANY; nexthop_tab[num_ifindex].nexthop_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
} }
nexthop_tab[num_ifindex].ifindex = stream_getl(s); nexthop_tab[num_ifindex].ifindex = stream_getl(s);
nexthop_tab[num_ifindex].protocol_distance = distance; nexthop_tab[num_ifindex].protocol_distance = distance;
nexthop_tab[num_ifindex].route_metric = metric; nexthop_tab[num_ifindex].route_metric = metric;
++num_ifindex; ++num_ifindex;
break; break;
case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV6_IFINDEX:
if (num_ifindex >= tab_size) { nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET6;
char addr_str[100]; stream_get (&nexthop_tab[num_ifindex].nexthop_addr.u.prefix6, s, 16);
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); nexthop_tab[num_ifindex].ifindex = stream_getl (s);
zlog_warn("%s %s: found too many nexthop ifindexes (%d > %d) for address %s", nbr = pim_neighbor_find_if (if_lookup_by_index_vrf (nexthop_tab[num_ifindex].ifindex, VRF_DEFAULT));
__FILE__, __PRETTY_FUNCTION__, if (nbr)
(num_ifindex + 1), tab_size, addr_str); {
return num_ifindex; nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET;
} nexthop_tab[num_ifindex].nexthop_addr.u.prefix4 = nbr->source_addr;
nexthop_tab[num_ifindex].nexthop_addr.s_addr = stream_get_ipv4(s); }
length -= 4; ++num_ifindex;
nexthop_tab[num_ifindex].ifindex = 0;
nexthop_tab[num_ifindex].protocol_distance = distance;
nexthop_tab[num_ifindex].route_metric = metric;
if (PIM_DEBUG_ZEBRA) {
char addr_str[100];
char nexthop_str[100];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
pim_inet4_dump("<nexthop?>", nexthop_tab[num_ifindex].nexthop_addr, nexthop_str, sizeof(nexthop_str));
zlog_debug("%s %s: zebra returned recursive nexthop %s for address %s",
__FILE__, __PRETTY_FUNCTION__,
nexthop_str, addr_str);
}
++num_ifindex;
break; break;
default: default:
/* do nothing */ /* do nothing */
{ {
char addr_str[100]; char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_warn("%s %s: found non-ifindex nexthop type=%d for address %s", zlog_warn("%s %s: found non-ifindex nexthop type=%d for address %s",
__FILE__, __PRETTY_FUNCTION__, __FILE__, __PRETTY_FUNCTION__,
@ -295,16 +272,16 @@ static int zclient_read_nexthop(struct zclient *zlookup,
return num_ifindex; return num_ifindex;
} }
static int zclient_lookup_nexthop_once(struct zclient *zlookup, static int
struct pim_zlookup_nexthop nexthop_tab[], zclient_lookup_nexthop_once (struct pim_zlookup_nexthop nexthop_tab[],
const int tab_size, const int tab_size,
struct in_addr addr) struct in_addr addr)
{ {
struct stream *s; struct stream *s;
int ret; int ret;
if (PIM_DEBUG_ZEBRA) { if (PIM_DEBUG_PIM_TRACE_DETAIL) {
char addr_str[100]; char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s: addr=%s", zlog_debug("%s: addr=%s",
__PRETTY_FUNCTION__, __PRETTY_FUNCTION__,
@ -327,8 +304,8 @@ static int zclient_lookup_nexthop_once(struct zclient *zlookup,
ret = writen(zlookup->sock, s->data, stream_get_endp(s)); ret = writen(zlookup->sock, s->data, stream_get_endp(s));
if (ret < 0) { if (ret < 0) {
zlog_err("%s %s: writen() failure writing to zclient lookup socket", zlog_err("%s %s: writen() failure: %d writing to zclient lookup socket",
__FILE__, __PRETTY_FUNCTION__); __FILE__, __PRETTY_FUNCTION__, errno);
zclient_lookup_failed(zlookup); zclient_lookup_failed(zlookup);
return -2; return -2;
} }
@ -343,26 +320,28 @@ static int zclient_lookup_nexthop_once(struct zclient *zlookup,
tab_size, addr); tab_size, addr);
} }
int zclient_lookup_nexthop(struct zclient *zlookup, int
struct pim_zlookup_nexthop nexthop_tab[], zclient_lookup_nexthop (struct pim_zlookup_nexthop nexthop_tab[],
const int tab_size, const int tab_size,
struct in_addr addr, struct in_addr addr,
int max_lookup) int max_lookup)
{ {
int lookup; int lookup;
uint32_t route_metric = 0xFFFFFFFF; uint32_t route_metric = 0xFFFFFFFF;
uint8_t protocol_distance = 0xFF; uint8_t protocol_distance = 0xFF;
qpim_nexthop_lookups++;
for (lookup = 0; lookup < max_lookup; ++lookup) { for (lookup = 0; lookup < max_lookup; ++lookup) {
int num_ifindex; int num_ifindex;
int first_ifindex; int first_ifindex;
struct in_addr nexthop_addr; struct prefix nexthop_addr;
num_ifindex = zclient_lookup_nexthop_once(qpim_zclient_lookup, nexthop_tab, num_ifindex = zclient_lookup_nexthop_once(nexthop_tab,
PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr); tab_size, addr);
if (num_ifindex < 1) { if (num_ifindex < 1) {
if (PIM_DEBUG_ZEBRA) { if (PIM_DEBUG_ZEBRA) {
char addr_str[100]; char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s %s: lookup=%d/%d: could not find nexthop ifindex for address %s", zlog_debug("%s %s: lookup=%d/%d: could not find nexthop ifindex for address %s",
__FILE__, __PRETTY_FUNCTION__, __FILE__, __PRETTY_FUNCTION__,
@ -378,9 +357,13 @@ int zclient_lookup_nexthop(struct zclient *zlookup,
} }
/* /*
FIXME: Non-recursive nexthop ensured only for first ifindex. * FIXME: Non-recursive nexthop ensured only for first ifindex.
However, recursive route lookup should really be fixed in zebra daemon. * However, recursive route lookup should really be fixed in zebra daemon.
See also TODO T24. * See also TODO T24.
*
* So Zebra for NEXTHOP_TYPE_IPV4 returns the ifindex now since
* it was being stored. This Doesn't solve all cases of
* recursive lookup but for the most common types it does.
*/ */
first_ifindex = nexthop_tab[0].ifindex; first_ifindex = nexthop_tab[0].ifindex;
nexthop_addr = nexthop_tab[0].nexthop_addr; nexthop_addr = nexthop_tab[0].nexthop_addr;
@ -390,7 +373,7 @@ int zclient_lookup_nexthop(struct zclient *zlookup,
if (lookup > 0) { if (lookup > 0) {
/* Report non-recursive success after first lookup */ /* Report non-recursive success after first lookup */
if (PIM_DEBUG_ZEBRA) { if (PIM_DEBUG_ZEBRA) {
char addr_str[100]; char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s %s: lookup=%d/%d: found non-recursive ifindex=%d for address %s dist=%d met=%d", zlog_debug("%s %s: lookup=%d/%d: found non-recursive ifindex=%d for address %s dist=%d met=%d",
__FILE__, __PRETTY_FUNCTION__, __FILE__, __PRETTY_FUNCTION__,
@ -400,7 +383,7 @@ int zclient_lookup_nexthop(struct zclient *zlookup,
} }
/* use last address as nexthop address */ /* use last address as nexthop address */
nexthop_tab[0].nexthop_addr = addr; nexthop_tab[0].nexthop_addr.u.prefix4 = addr;
/* report original route metric/distance */ /* report original route metric/distance */
nexthop_tab[0].route_metric = route_metric; nexthop_tab[0].route_metric = route_metric;
@ -411,10 +394,10 @@ int zclient_lookup_nexthop(struct zclient *zlookup,
} }
if (PIM_DEBUG_ZEBRA) { if (PIM_DEBUG_ZEBRA) {
char addr_str[100]; char addr_str[INET_ADDRSTRLEN];
char nexthop_str[100]; char nexthop_str[PREFIX_STRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
pim_inet4_dump("<nexthop?>", nexthop_addr, nexthop_str, sizeof(nexthop_str)); pim_addr_dump("<nexthop?>", &nexthop_addr, nexthop_str, sizeof(nexthop_str));
zlog_debug("%s %s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s dist=%d met=%d", zlog_debug("%s %s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s dist=%d met=%d",
__FILE__, __PRETTY_FUNCTION__, __FILE__, __PRETTY_FUNCTION__,
lookup, max_lookup, nexthop_str, addr_str, lookup, max_lookup, nexthop_str, addr_str,
@ -422,12 +405,12 @@ int zclient_lookup_nexthop(struct zclient *zlookup,
nexthop_tab[0].route_metric); nexthop_tab[0].route_metric);
} }
addr = nexthop_addr; /* use nexthop addr for recursive lookup */ addr = nexthop_addr.u.prefix4; /* use nexthop addr for recursive lookup */
} /* for (max_lookup) */ } /* for (max_lookup) */
if (PIM_DEBUG_ZEBRA) { if (PIM_DEBUG_ZEBRA) {
char addr_str[100]; char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_warn("%s %s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %s", zlog_warn("%s %s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %s",
__FILE__, __PRETTY_FUNCTION__, __FILE__, __PRETTY_FUNCTION__,
@ -436,3 +419,100 @@ int zclient_lookup_nexthop(struct zclient *zlookup,
return -2; return -2;
} }
void
pim_zlookup_show_ip_multicast (struct vty *vty)
{
vty_out(vty, "Zclient lookup socket: ");
if (zlookup) {
vty_out(vty, "%d failures=%d%s", zlookup->sock,
zlookup->fail, VTY_NEWLINE);
}
else {
vty_out(vty, "<null zclient>%s", VTY_NEWLINE);
}
}
int
pim_zlookup_sg_statistics (struct channel_oil *c_oil)
{
struct stream *s = zlookup->obuf;
uint16_t command = 0;
unsigned long long lastused;
struct prefix_sg sg;
int count = 0;
int ret;
struct interface *ifp = pim_if_find_by_vif_index (c_oil->oil.mfcc_parent);
if (PIM_DEBUG_ZEBRA)
{
struct prefix_sg more;
more.src = c_oil->oil.mfcc_origin;
more.grp = c_oil->oil.mfcc_mcastgrp;
zlog_debug ("Sending Request for New Channel Oil Information(%s)", pim_str_sg_dump (&more));
}
if (!ifp)
return -1;
stream_reset (s);
zclient_create_header (s, ZEBRA_IPMR_ROUTE_STATS, VRF_DEFAULT);
stream_put_in_addr (s, &c_oil->oil.mfcc_origin);
stream_put_in_addr (s, &c_oil->oil.mfcc_mcastgrp);
stream_putl (s, ifp->ifindex);
stream_putw_at(s, 0, stream_get_endp(s));
count = stream_get_endp (s);
ret = writen (zlookup->sock, s->data, count);
if (ret <= 0)
{
zlog_err("%s %s: writen() failure: %d writing to zclient lookup socket",
__FILE__, __PRETTY_FUNCTION__, errno);
return -1;
}
s = zlookup->ibuf;
while (command != ZEBRA_IPMR_ROUTE_STATS)
{
int err;
uint16_t length = 0;
vrf_id_t vrf_id;
u_char marker;
u_char version;
stream_reset (s);
err = zclient_read_header (s, zlookup->sock, &length, &marker, &version,
&vrf_id, &command);
if (err < 0)
{
zlog_err ("%s %s: zclient_read_header() failed",
__FILE__, __PRETTY_FUNCTION__);
zclient_lookup_failed(zlookup);
return -1;
}
}
sg.src.s_addr = stream_get_ipv4 (s);
sg.grp.s_addr = stream_get_ipv4 (s);
if (sg.src.s_addr != c_oil->oil.mfcc_origin.s_addr ||
sg.grp.s_addr != c_oil->oil.mfcc_mcastgrp.s_addr)
{
zlog_err ("%s: Received wrong %s information",
__PRETTY_FUNCTION__, pim_str_sg_dump (&sg));
zclient_lookup_failed (zlookup);
return -3;
}
stream_get (&lastused, s, sizeof (lastused));
ret = stream_getl (s);
if (PIM_DEBUG_ZEBRA)
zlog_debug ("Received %lld for %s success: %d", lastused, pim_str_sg_dump (&sg), ret);
c_oil->cc.lastused = lastused;
return 0;
}

View File

@ -28,18 +28,20 @@
#define PIM_NEXTHOP_LOOKUP_MAX (3) /* max. recursive route lookup */ #define PIM_NEXTHOP_LOOKUP_MAX (3) /* max. recursive route lookup */
struct pim_zlookup_nexthop { struct pim_zlookup_nexthop {
struct in_addr nexthop_addr; struct prefix nexthop_addr;
ifindex_t ifindex; ifindex_t ifindex;
uint32_t route_metric; uint32_t route_metric;
uint8_t protocol_distance; uint8_t protocol_distance;
}; };
struct zclient *zclient_lookup_new(void); void zclient_lookup_new (void);
int zclient_lookup_nexthop(struct zclient *zlookup, int zclient_lookup_nexthop(struct pim_zlookup_nexthop nexthop_tab[],
struct pim_zlookup_nexthop nexthop_tab[],
const int tab_size, const int tab_size,
struct in_addr addr, struct in_addr addr,
int max_lookup); int max_lookup);
void pim_zlookup_show_ip_multicast (struct vty *vty);
int pim_zlookup_sg_statistics (struct channel_oil *c_oil);
#endif /* PIM_ZLOOKUP_H */ #endif /* PIM_ZLOOKUP_H */

View File

@ -23,6 +23,9 @@
#include "log.h" #include "log.h"
#include "memory.h" #include "memory.h"
#include "if.h" #include "if.h"
#include "prefix.h"
#include "vty.h"
#include "plist.h"
#include "pimd.h" #include "pimd.h"
#include "pim_cmd.h" #include "pim_cmd.h"
@ -35,6 +38,7 @@
#include "pim_rpf.h" #include "pim_rpf.h"
#include "pim_ssmpingd.h" #include "pim_ssmpingd.h"
#include "pim_static.h" #include "pim_static.h"
#include "pim_rp.h"
const char *const PIM_ALL_SYSTEMS = MCAST_ALL_SYSTEMS; const char *const PIM_ALL_SYSTEMS = MCAST_ALL_SYSTEMS;
const char *const PIM_ALL_ROUTERS = MCAST_ALL_ROUTERS; const char *const PIM_ALL_ROUTERS = MCAST_ALL_ROUTERS;
@ -45,21 +49,17 @@ struct thread_master *master = NULL;
uint32_t qpim_debugs = 0; uint32_t qpim_debugs = 0;
int qpim_mroute_socket_fd = -1; int qpim_mroute_socket_fd = -1;
int64_t qpim_mroute_socket_creation = 0; /* timestamp of creation */ int64_t qpim_mroute_socket_creation = 0; /* timestamp of creation */
struct thread *qpim_mroute_socket_reader = 0;
int qpim_mroute_oif_highest_vif_index = -1; int qpim_mroute_oif_highest_vif_index = -1;
struct list *qpim_channel_oil_list = 0;
int qpim_t_periodic = PIM_DEFAULT_T_PERIODIC; /* Period between Join/Prune Messages */ int qpim_t_periodic = PIM_DEFAULT_T_PERIODIC; /* Period between Join/Prune Messages */
struct list *qpim_upstream_list = 0; struct zclient *qpim_zclient_update = NULL;
struct zclient *qpim_zclient_update = 0;
struct zclient *qpim_zclient_lookup = 0;
struct pim_assert_metric qpim_infinite_assert_metric; struct pim_assert_metric qpim_infinite_assert_metric;
long qpim_rpf_cache_refresh_delay_msec = 10000; long qpim_rpf_cache_refresh_delay_msec = 50;
struct thread *qpim_rpf_cache_refresher = 0; struct thread *qpim_rpf_cache_refresher = NULL;
int64_t qpim_rpf_cache_refresh_requests = 0; int64_t qpim_rpf_cache_refresh_requests = 0;
int64_t qpim_rpf_cache_refresh_events = 0; int64_t qpim_rpf_cache_refresh_events = 0;
int64_t qpim_rpf_cache_refresh_last = 0; int64_t qpim_rpf_cache_refresh_last = 0;
struct in_addr qpim_inaddr_any; struct in_addr qpim_inaddr_any;
struct list *qpim_ssmpingd_list = 0; struct list *qpim_ssmpingd_list = NULL;
struct in_addr qpim_ssmpingd_group_addr; struct in_addr qpim_ssmpingd_group_addr;
int64_t qpim_scan_oil_events = 0; int64_t qpim_scan_oil_events = 0;
int64_t qpim_scan_oil_last = 0; int64_t qpim_scan_oil_last = 0;
@ -67,8 +67,11 @@ int64_t qpim_mroute_add_events = 0;
int64_t qpim_mroute_add_last = 0; int64_t qpim_mroute_add_last = 0;
int64_t qpim_mroute_del_events = 0; int64_t qpim_mroute_del_events = 0;
int64_t qpim_mroute_del_last = 0; int64_t qpim_mroute_del_last = 0;
struct list *qpim_static_route_list = 0; struct list *qpim_static_route_list = NULL;
struct pim_rpf qpim_rp = { .rpf_addr.s_addr = INADDR_NONE }; unsigned int qpim_keep_alive_time = PIM_KEEPALIVE_PERIOD;
signed int qpim_rp_keep_alive_time = 0;
int64_t qpim_nexthop_lookups = 0;
int qpim_packet_process = PIM_DEFAULT_PACKET_PROCESS;
int32_t qpim_register_suppress_time = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT; int32_t qpim_register_suppress_time = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT;
int32_t qpim_register_probe_time = PIM_REGISTER_PROBE_TIME_DEFAULT; int32_t qpim_register_probe_time = PIM_REGISTER_PROBE_TIME_DEFAULT;
@ -77,22 +80,28 @@ static void pim_free()
{ {
pim_ssmpingd_destroy(); pim_ssmpingd_destroy();
if (qpim_channel_oil_list) pim_oil_terminate ();
list_free(qpim_channel_oil_list);
if (qpim_upstream_list) pim_upstream_terminate ();
list_free(qpim_upstream_list);
if (qpim_static_route_list) if (qpim_static_route_list)
list_free(qpim_static_route_list); list_free(qpim_static_route_list);
pim_route_map_terminate(); pim_route_map_terminate();
pim_if_terminate ();
pim_rp_free ();
pim_route_map_terminate();
} }
void pim_init() void pim_init()
{ {
srandom(time(NULL)); srandom(time(NULL));
qpim_rp_keep_alive_time = PIM_RP_KEEPALIVE_PERIOD;
pim_rp_init ();
if (!inet_aton(PIM_ALL_PIM_ROUTERS, &qpim_all_pim_routers_addr)) { if (!inet_aton(PIM_ALL_PIM_ROUTERS, &qpim_all_pim_routers_addr)) {
zlog_err("%s %s: could not solve %s to group address: errno=%d: %s", zlog_err("%s %s: could not solve %s to group address: errno=%d: %s",
__FILE__, __PRETTY_FUNCTION__, __FILE__, __PRETTY_FUNCTION__,
@ -101,22 +110,9 @@ void pim_init()
return; return;
} }
qpim_channel_oil_list = list_new(); pim_oil_init ();
if (!qpim_channel_oil_list) {
zlog_err("%s %s: failure: channel_oil_list=list_new()",
__FILE__, __PRETTY_FUNCTION__);
return;
}
qpim_channel_oil_list->del = (void (*)(void *)) pim_channel_oil_free;
qpim_upstream_list = list_new(); pim_upstream_init ();
if (!qpim_upstream_list) {
zlog_err("%s %s: failure: upstream_list=list_new()",
__FILE__, __PRETTY_FUNCTION__);
pim_free();
return;
}
qpim_upstream_list->del = (void (*)(void *)) pim_upstream_free;
qpim_static_route_list = list_new(); qpim_static_route_list = list_new();
if (!qpim_static_route_list) { if (!qpim_static_route_list) {
@ -129,9 +125,6 @@ void pim_init()
qpim_mroute_socket_fd = -1; /* mark mroute as disabled */ qpim_mroute_socket_fd = -1; /* mark mroute as disabled */
qpim_mroute_oif_highest_vif_index = -1; qpim_mroute_oif_highest_vif_index = -1;
zassert(!qpim_debugs);
zassert(!PIM_MROUTE_IS_ENABLED);
qpim_inaddr_any.s_addr = PIM_NET_INADDR_ANY; qpim_inaddr_any.s_addr = PIM_NET_INADDR_ANY;
/* /*

View File

@ -23,13 +23,13 @@
#include <stdint.h> #include <stdint.h>
#include "pim_str.h"
#include "pim_memory.h" #include "pim_memory.h"
#include "pim_assert.h" #include "pim_assert.h"
#define PIMD_PROGNAME "pimd" #define PIMD_PROGNAME "pimd"
#define PIMD_DEFAULT_CONFIG "pimd.conf" #define PIMD_DEFAULT_CONFIG "pimd.conf"
#define PIMD_VTY_PORT 2611 #define PIMD_VTY_PORT 2611
#define PIMD_BUG_ADDRESS "https://github.com/udhos/qpimd"
#define PIM_IP_HEADER_MIN_LEN (20) #define PIM_IP_HEADER_MIN_LEN (20)
#define PIM_IP_HEADER_MAX_LEN (60) #define PIM_IP_HEADER_MAX_LEN (60)
@ -51,6 +51,8 @@
#define PIM_INADDR_IS_ANY(addr) (addr).s_addr == PIM_NET_INADDR_ANY #define PIM_INADDR_IS_ANY(addr) (addr).s_addr == PIM_NET_INADDR_ANY
#define PIM_INADDR_ISNOT_ANY(addr) ((addr).s_addr != PIM_NET_INADDR_ANY) /* struct in_addr addr */ #define PIM_INADDR_ISNOT_ANY(addr) ((addr).s_addr != PIM_NET_INADDR_ANY) /* struct in_addr addr */
#define max(x,y) ((x) > (y) ? (x) : (y))
#define PIM_MASK_PIM_EVENTS (1 << 0) #define PIM_MASK_PIM_EVENTS (1 << 0)
#define PIM_MASK_PIM_EVENTS_DETAIL (1 << 1) #define PIM_MASK_PIM_EVENTS_DETAIL (1 << 1)
#define PIM_MASK_PIM_PACKETS (1 << 2) #define PIM_MASK_PIM_PACKETS (1 << 2)
@ -65,9 +67,28 @@
#define PIM_MASK_ZEBRA (1 << 11) #define PIM_MASK_ZEBRA (1 << 11)
#define PIM_MASK_SSMPINGD (1 << 12) #define PIM_MASK_SSMPINGD (1 << 12)
#define PIM_MASK_MROUTE (1 << 13) #define PIM_MASK_MROUTE (1 << 13)
#define PIM_MASK_PIM_HELLO (1 << 14) #define PIM_MASK_MROUTE_DETAIL (1 << 14)
#define PIM_MASK_PIM_J_P (1 << 15) #define PIM_MASK_PIM_HELLO (1 << 15)
#define PIM_MASK_STATIC (1 << 16) #define PIM_MASK_PIM_J_P (1 << 16)
#define PIM_MASK_STATIC (1 << 17)
#define PIM_MASK_PIM_REG (1 << 18)
#define PIM_MASK_MSDP_EVENTS (1 << 19)
#define PIM_MASK_MSDP_PACKETS (1 << 20)
#define PIM_MASK_MSDP_INTERNAL (1 << 21)
/* PIM error codes */
#define PIM_SUCCESS 0
#define PIM_MALLOC_FAIL -1
#define PIM_GROUP_BAD_ADDRESS -2
#define PIM_GROUP_OVERLAP -3
#define PIM_GROUP_PFXLIST_OVERLAP -4
#define PIM_RP_BAD_ADDRESS -5
#define PIM_RP_NO_PATH -6
#define PIM_RP_NOT_FOUND -7
#define PIM_RP_PFXLIST_IN_USE -8
#define PIM_IFACE_NOT_FOUND -9
#define PIM_UPDATE_SOURCE_DUP -10
const char *const PIM_ALL_SYSTEMS; const char *const PIM_ALL_SYSTEMS;
const char *const PIM_ALL_ROUTERS; const char *const PIM_ALL_ROUTERS;
@ -78,14 +99,10 @@ extern struct thread_master *master;
uint32_t qpim_debugs; uint32_t qpim_debugs;
int qpim_mroute_socket_fd; int qpim_mroute_socket_fd;
int64_t qpim_mroute_socket_creation; /* timestamp of creation */ int64_t qpim_mroute_socket_creation; /* timestamp of creation */
struct thread *qpim_mroute_socket_reader;
int qpim_mroute_oif_highest_vif_index; int qpim_mroute_oif_highest_vif_index;
struct list *qpim_channel_oil_list; /* list of struct channel_oil */
struct in_addr qpim_all_pim_routers_addr; struct in_addr qpim_all_pim_routers_addr;
int qpim_t_periodic; /* Period between Join/Prune Messages */ int qpim_t_periodic; /* Period between Join/Prune Messages */
struct list *qpim_upstream_list; /* list of struct pim_upstream */
struct zclient *qpim_zclient_update; struct zclient *qpim_zclient_update;
struct zclient *qpim_zclient_lookup;
struct pim_assert_metric qpim_infinite_assert_metric; struct pim_assert_metric qpim_infinite_assert_metric;
long qpim_rpf_cache_refresh_delay_msec; long qpim_rpf_cache_refresh_delay_msec;
struct thread *qpim_rpf_cache_refresher; struct thread *qpim_rpf_cache_refresher;
@ -101,8 +118,12 @@ int64_t qpim_mroute_add_events;
int64_t qpim_mroute_add_last; int64_t qpim_mroute_add_last;
int64_t qpim_mroute_del_events; int64_t qpim_mroute_del_events;
int64_t qpim_mroute_del_last; int64_t qpim_mroute_del_last;
int64_t qpim_nexthop_lookups;
struct list *qpim_static_route_list; /* list of routes added statically */ struct list *qpim_static_route_list; /* list of routes added statically */
struct pim_rpf qpim_rp; extern unsigned int qpim_keep_alive_time;
extern signed int qpim_rp_keep_alive_time;
extern int qpim_packet_process;
#define PIM_DEFAULT_PACKET_PROCESS 3
#define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2) #define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2)
@ -132,12 +153,17 @@ extern int32_t qpim_register_probe_time;
#define PIM_DEBUG_ZEBRA (qpim_debugs & PIM_MASK_ZEBRA) #define PIM_DEBUG_ZEBRA (qpim_debugs & PIM_MASK_ZEBRA)
#define PIM_DEBUG_SSMPINGD (qpim_debugs & PIM_MASK_SSMPINGD) #define PIM_DEBUG_SSMPINGD (qpim_debugs & PIM_MASK_SSMPINGD)
#define PIM_DEBUG_MROUTE (qpim_debugs & PIM_MASK_MROUTE) #define PIM_DEBUG_MROUTE (qpim_debugs & PIM_MASK_MROUTE)
#define PIM_DEBUG_MROUTE_DETAIL (qpim_debugs & PIM_MASK_MROUTE_DETAIL)
#define PIM_DEBUG_PIM_HELLO (qpim_debugs & PIM_MASK_PIM_HELLO) #define PIM_DEBUG_PIM_HELLO (qpim_debugs & PIM_MASK_PIM_HELLO)
#define PIM_DEBUG_PIM_J_P (qpim_debugs & PIM_MASK_PIM_J_P) #define PIM_DEBUG_PIM_J_P (qpim_debugs & PIM_MASK_PIM_J_P)
#define PIM_DEBUG_PIM_REG (qpim_debugs & PIM_MASK_PIM_REG)
#define PIM_DEBUG_STATIC (qpim_debugs & PIM_MASK_STATIC) #define PIM_DEBUG_STATIC (qpim_debugs & PIM_MASK_STATIC)
#define PIM_DEBUG_MSDP_EVENTS (qpim_debugs & PIM_MASK_MSDP_EVENTS)
#define PIM_DEBUG_MSDP_PACKETS (qpim_debugs & PIM_MASK_MSDP_PACKETS)
#define PIM_DEBUG_MSDP_INTERNAL (qpim_debugs & PIM_MASK_MSDP_INTERNAL)
#define PIM_DEBUG_EVENTS (qpim_debugs & (PIM_MASK_PIM_EVENTS | PIM_MASK_IGMP_EVENTS)) #define PIM_DEBUG_EVENTS (qpim_debugs & (PIM_MASK_PIM_EVENTS | PIM_MASK_IGMP_EVENTS | PIM_MASK_MSDP_EVENTS))
#define PIM_DEBUG_PACKETS (qpim_debugs & (PIM_MASK_PIM_PACKETS | PIM_MASK_IGMP_PACKETS)) #define PIM_DEBUG_PACKETS (qpim_debugs & (PIM_MASK_PIM_PACKETS | PIM_MASK_IGMP_PACKETS | PIM_MASK_MSDP_PACKETS))
#define PIM_DEBUG_TRACE (qpim_debugs & (PIM_MASK_PIM_TRACE | PIM_MASK_IGMP_TRACE)) #define PIM_DEBUG_TRACE (qpim_debugs & (PIM_MASK_PIM_TRACE | PIM_MASK_IGMP_TRACE))
#define PIM_DO_DEBUG_PIM_EVENTS (qpim_debugs |= PIM_MASK_PIM_EVENTS) #define PIM_DO_DEBUG_PIM_EVENTS (qpim_debugs |= PIM_MASK_PIM_EVENTS)
@ -152,9 +178,14 @@ extern int32_t qpim_register_probe_time;
#define PIM_DO_DEBUG_ZEBRA (qpim_debugs |= PIM_MASK_ZEBRA) #define PIM_DO_DEBUG_ZEBRA (qpim_debugs |= PIM_MASK_ZEBRA)
#define PIM_DO_DEBUG_SSMPINGD (qpim_debugs |= PIM_MASK_SSMPINGD) #define PIM_DO_DEBUG_SSMPINGD (qpim_debugs |= PIM_MASK_SSMPINGD)
#define PIM_DO_DEBUG_MROUTE (qpim_debugs |= PIM_MASK_MROUTE) #define PIM_DO_DEBUG_MROUTE (qpim_debugs |= PIM_MASK_MROUTE)
#define PIM_DO_DEBUG_MROUTE_DETAIL (qpim_debugs |= PIM_MASK_MROUTE_DETAIL)
#define PIM_DO_DEBUG_PIM_HELLO (qpim_debugs |= PIM_MASK_PIM_HELLO) #define PIM_DO_DEBUG_PIM_HELLO (qpim_debugs |= PIM_MASK_PIM_HELLO)
#define PIM_DO_DEBUG_PIM_J_P (qpim_debugs |= PIM_MASK_PIM_J_P) #define PIM_DO_DEBUG_PIM_J_P (qpim_debugs |= PIM_MASK_PIM_J_P)
#define PIM_DO_DEBUG_PIM_REG (qpim_debugs |= PIM_MASK_PIM_REG)
#define PIM_DO_DEBUG_STATIC (qpim_debugs |= PIM_MASK_STATIC) #define PIM_DO_DEBUG_STATIC (qpim_debugs |= PIM_MASK_STATIC)
#define PIM_DO_DEBUG_MSDP_EVENTS (qpim_debugs |= PIM_MASK_MSDP_EVENTS)
#define PIM_DO_DEBUG_MSDP_PACKETS (qpim_debugs |= PIM_MASK_MSDP_PACKETS)
#define PIM_DO_DEBUG_MSDP_INTERNAL (qpim_debugs |= PIM_MASK_MSDP_INTERNAL)
#define PIM_DONT_DEBUG_PIM_EVENTS (qpim_debugs &= ~PIM_MASK_PIM_EVENTS) #define PIM_DONT_DEBUG_PIM_EVENTS (qpim_debugs &= ~PIM_MASK_PIM_EVENTS)
#define PIM_DONT_DEBUG_PIM_PACKETS (qpim_debugs &= ~PIM_MASK_PIM_PACKETS) #define PIM_DONT_DEBUG_PIM_PACKETS (qpim_debugs &= ~PIM_MASK_PIM_PACKETS)
@ -168,9 +199,14 @@ extern int32_t qpim_register_probe_time;
#define PIM_DONT_DEBUG_ZEBRA (qpim_debugs &= ~PIM_MASK_ZEBRA) #define PIM_DONT_DEBUG_ZEBRA (qpim_debugs &= ~PIM_MASK_ZEBRA)
#define PIM_DONT_DEBUG_SSMPINGD (qpim_debugs &= ~PIM_MASK_SSMPINGD) #define PIM_DONT_DEBUG_SSMPINGD (qpim_debugs &= ~PIM_MASK_SSMPINGD)
#define PIM_DONT_DEBUG_MROUTE (qpim_debugs &= ~PIM_MASK_MROUTE) #define PIM_DONT_DEBUG_MROUTE (qpim_debugs &= ~PIM_MASK_MROUTE)
#define PIM_DONT_DEBUG_MROUTE_DETAIL (qpim_debugs &= ~PIM_MASK_MROUTE_DETAIL)
#define PIM_DONT_DEBUG_PIM_HELLO (qpim_debugs &= ~PIM_MASK_PIM_HELLO) #define PIM_DONT_DEBUG_PIM_HELLO (qpim_debugs &= ~PIM_MASK_PIM_HELLO)
#define PIM_DONT_DEBUG_PIM_J_P (qpim_debugs &= ~PIM_MASK_PIM_J_P) #define PIM_DONT_DEBUG_PIM_J_P (qpim_debugs &= ~PIM_MASK_PIM_J_P)
#define PIM_DONT_DEBUG_PIM_REG (qpim_debugs &= ~PIM_MASK_PIM_REG)
#define PIM_DONT_DEBUG_STATIC (qpim_debugs &= ~PIM_MASK_STATIC) #define PIM_DONT_DEBUG_STATIC (qpim_debugs &= ~PIM_MASK_STATIC)
#define PIM_DONT_DEBUG_MSDP_EVENTS (qpim_debugs &= ~PIM_MASK_MSDP_EVENTS)
#define PIM_DONT_DEBUG_MSDP_PACKETS (qpim_debugs &= ~PIM_MASK_MSDP_PACKETS)
#define PIM_DONT_DEBUG_MSDP_INTERNAL (qpim_debugs &= ~PIM_MASK_MSDP_INTERNAL)
void pim_init(void); void pim_init(void);
void pim_terminate(void); void pim_terminate(void);

View File

@ -44,7 +44,7 @@ zebra_SOURCES = \
irdp_main.c irdp_interface.c irdp_packet.c router-id.c zebra_fpm.c \ irdp_main.c irdp_interface.c irdp_packet.c router-id.c zebra_fpm.c \
$(othersrc) zebra_ptm.c zebra_rnh.c zebra_ptm_redistribute.c \ $(othersrc) zebra_ptm.c zebra_rnh.c zebra_ptm_redistribute.c \
zebra_ns.c zebra_vrf.c zebra_static.c zebra_mpls.c zebra_mpls_vty.c \ zebra_ns.c zebra_vrf.c zebra_static.c zebra_mpls.c zebra_mpls_vty.c \
$(protobuf_srcs) \ $(protobuf_srcs) zebra_mroute.c \
$(dev_srcs) $(dev_srcs)
testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \ testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \
@ -60,7 +60,7 @@ noinst_HEADERS = \
rt_netlink.h zebra_fpm.h zebra_fpm_private.h zebra_rnh.h \ rt_netlink.h zebra_fpm.h zebra_fpm_private.h zebra_rnh.h \
zebra_ptm_redistribute.h zebra_ptm.h zebra_routemap.h \ zebra_ptm_redistribute.h zebra_ptm.h zebra_routemap.h \
zebra_ns.h zebra_vrf.h ioctl_solaris.h zebra_static.h zebra_mpls.h \ zebra_ns.h zebra_vrf.h ioctl_solaris.h zebra_static.h zebra_mpls.h \
kernel_netlink.h if_netlink.h kernel_netlink.h if_netlink.h zebra_mroute.h
zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) $(Q_FPM_PB_CLIENT_LDOPTS) zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) $(Q_FPM_PB_CLIENT_LDOPTS)

View File

@ -173,6 +173,48 @@ netlink_to_zebra_link_type (unsigned int hwt)
} }
} }
//Temporary Assignments to compile on older platforms.
#ifndef IFLA_BR_MAX
#define IFLA_BR_MAX 39
#endif
#ifndef IFLA_VXLAN_ID
#define IFLA_VXLAN_ID 1
#endif
#ifndef IFLA_VXLAN_LOCAL
#define IFLA_VXLAN_LOCAL 4
#endif
#ifndef IFLA_VXLAN_MAX
#define IFLA_VXLAN_MAX 26
#endif
#ifndef IFLA_BRIDGE_MAX
#define IFLA_BRIDGE_MAX 2
#endif
#ifndef IFLA_BRIDGE_VLAN_INFO
#define IFLA_BRIDGE_VLAN_INFO 2
#endif
#ifndef BRIDGE_VLAN_INFO_PVID
#define BRIDGE_VLAN_INFO_PVID (1<<1)
#endif
#ifndef RTEXT_FILTER_BRVLAN
#define RTEXT_FILTER_BRVLAN (1<<1)
#endif
#ifndef NTF_SELF
#define NTF_SELF 0x02
#endif
#ifndef IFLA_BR_VLAN_FILTERING
#define IFLA_BR_VLAN_FILTERING 7
#endif
#define parse_rtattr_nested(tb, max, rta) \ #define parse_rtattr_nested(tb, max, rta) \
netlink_parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta)) netlink_parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta))

View File

@ -60,3 +60,5 @@ int kernel_neigh_update (int a, int b, uint32_t c, char *d, int e)
void kernel_init (struct zebra_ns *zns) { return; } void kernel_init (struct zebra_ns *zns) { return; }
void kernel_terminate (struct zebra_ns *zns) { return; } void kernel_terminate (struct zebra_ns *zns) { return; }
void route_read (struct zebra_ns *zns) { return; } void route_read (struct zebra_ns *zns) { return; }
int kernel_get_ipmr_sg_stats (void *m) { return 0; }

View File

@ -40,4 +40,5 @@ extern int kernel_upd_lsp (zebra_lsp_t *);
extern int kernel_del_lsp (zebra_lsp_t *); extern int kernel_del_lsp (zebra_lsp_t *);
extern int mpls_kernel_init (void); extern int mpls_kernel_init (void);
extern int kernel_get_ipmr_sg_stats (void *mroute);
#endif /* _ZEBRA_RT_H */ #endif /* _ZEBRA_RT_H */

View File

@ -55,6 +55,8 @@
#include "zebra/zebra_mpls.h" #include "zebra/zebra_mpls.h"
#include "zebra/kernel_netlink.h" #include "zebra/kernel_netlink.h"
#include "zebra/rt_netlink.h" #include "zebra/rt_netlink.h"
#include "zebra/zebra_mroute.h"
/* TODO - Temporary definitions, need to refine. */ /* TODO - Temporary definitions, need to refine. */
#ifndef AF_MPLS #ifndef AF_MPLS
@ -88,6 +90,10 @@
#ifndef MPLS_IPTUNNEL_DST #ifndef MPLS_IPTUNNEL_DST
#define MPLS_IPTUNNEL_DST 1 #define MPLS_IPTUNNEL_DST 1
#endif #endif
#ifndef NDA_MASTER
#define NDA_MASTER 9
#endif
/* End of temporary definitions */ /* End of temporary definitions */
struct gw_family_t struct gw_family_t
@ -520,15 +526,17 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
return 0; return 0;
} }
static struct mcast_route_data *mroute = NULL;
static int static int
netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h, netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
ns_id_t ns_id) ns_id_t ns_id)
{ {
int len; int len;
unsigned long long lastused = 0;
struct rtmsg *rtm; struct rtmsg *rtm;
struct rtattr *tb[RTA_MAX + 1]; struct rtattr *tb[RTA_MAX + 1];
struct prefix_sg sg; struct mcast_route_data *m;
struct mcast_route_data mr;
int iif = 0; int iif = 0;
int count; int count;
int oif[256]; int oif[256];
@ -536,10 +544,16 @@ netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h
char sbuf[40]; char sbuf[40];
char gbuf[40]; char gbuf[40];
char oif_list[256] = "\0"; char oif_list[256] = "\0";
memset (&sg, 0, sizeof (sg));
sg.family = IANA_AFI_IPMR;
vrf_id_t vrf = ns_id; vrf_id_t vrf = ns_id;
if (mroute)
m = mroute;
else
{
memset (&mr, 0, sizeof (mr));
m = &mr;
}
rtm = NLMSG_DATA (h); rtm = NLMSG_DATA (h);
len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg)); len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
@ -551,13 +565,13 @@ netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h
iif = *(int *)RTA_DATA (tb[RTA_IIF]); iif = *(int *)RTA_DATA (tb[RTA_IIF]);
if (tb[RTA_SRC]) if (tb[RTA_SRC])
sg.src = *(struct in_addr *)RTA_DATA (tb[RTA_SRC]); m->sg.src = *(struct in_addr *)RTA_DATA (tb[RTA_SRC]);
if (tb[RTA_DST]) if (tb[RTA_DST])
sg.grp = *(struct in_addr *)RTA_DATA (tb[RTA_DST]); m->sg.grp = *(struct in_addr *)RTA_DATA (tb[RTA_DST]);
if ((RTA_EXPIRES <= RTA_MAX) && tb[RTA_EXPIRES]) if ((RTA_EXPIRES <= RTA_MAX) && tb[RTA_EXPIRES])
lastused = *(unsigned long long *)RTA_DATA (tb[RTA_EXPIRES]); m->lastused = *(unsigned long long *)RTA_DATA (tb[RTA_EXPIRES]);
if (tb[RTA_MULTIPATH]) if (tb[RTA_MULTIPATH])
{ {
@ -580,18 +594,20 @@ netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h
if (IS_ZEBRA_DEBUG_KERNEL) if (IS_ZEBRA_DEBUG_KERNEL)
{ {
strcpy (sbuf, inet_ntoa (sg.src)); struct interface *ifp;
strcpy (gbuf, inet_ntoa (sg.grp)); strcpy (sbuf, inet_ntoa (m->sg.src));
strcpy (gbuf, inet_ntoa (m->sg.grp));
for (count = 0; count < oif_count; count++) for (count = 0; count < oif_count; count++)
{ {
struct interface *ifp = if_lookup_by_index_vrf (oif[count], vrf); ifp = if_lookup_by_index_vrf (oif[count], vrf);
char temp[256]; char temp[256];
sprintf (temp, "%s ", ifp->name); sprintf (temp, "%s ", ifp->name);
strcat (oif_list, temp); strcat (oif_list, temp);
} }
zlog_debug ("MCAST %s (%s,%s) IIF: %d OIF: %s jiffies: %lld", ifp = if_lookup_by_index_vrf (iif, vrf);
nl_msg_type_to_str (h->nlmsg_type), sbuf, gbuf, iif, oif_list, lastused); zlog_debug ("MCAST %s (%s,%s) IIF: %s OIF: %s jiffies: %lld",
nl_msg_type_to_str(h->nlmsg_type), sbuf, gbuf, ifp->name, oif_list, m->lastused);
} }
return 0; return 0;
} }
@ -1509,6 +1525,39 @@ skip:
return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns); return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns);
} }
int
kernel_get_ipmr_sg_stats (void *in)
{
int suc = 0;
struct mcast_route_data *mr = (struct mcast_route_data *)in;
struct {
struct nlmsghdr n;
struct ndmsg ndm;
char buf[256];
} req;
mroute = mr;
struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT);
memset(&req.n, 0, sizeof(req.n));
memset(&req.ndm, 0, sizeof(req.ndm));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
req.ndm.ndm_family = AF_INET;
req.n.nlmsg_type = RTM_GETROUTE;
addattr_l (&req.n, sizeof (req), RTA_IIF, &mroute->ifindex, 4);
addattr_l (&req.n, sizeof (req), RTA_OIF, &mroute->ifindex, 4);
addattr_l (&req.n, sizeof (req), RTA_SRC, &mroute->sg.src.s_addr, 4);
addattr_l (&req.n, sizeof (req), RTA_DST, &mroute->sg.grp.s_addr, 4);
suc = netlink_talk (netlink_route_change_read_multicast, &req.n, &zns->netlink_cmd, zns);
mroute = NULL;
return suc;
}
int int
kernel_route_rib (struct prefix *p, struct rib *old, struct rib *new) kernel_route_rib (struct prefix *p, struct rib *old, struct rib *new)
{ {

View File

@ -416,3 +416,9 @@ kernel_neigh_update (int add, int ifindex, uint32_t addr, char *lla, int llalen)
/* TODO */ /* TODO */
return 0; return 0;
} }
extern int
kernel_get_ipmr_sg_stats (void *mroute)
{
return 0;
}

View File

@ -28,6 +28,7 @@
#include "log.h" #include "log.h"
#include "rib.h" #include "rib.h"
#include "vty.h" #include "vty.h"
#include "prefix.h"
#include "zebra/zserv.h" #include "zebra/zserv.h"
#include "zebra/zebra_ns.h" #include "zebra/zebra_ns.h"

68
zebra/zebra_mroute.c Normal file
View File

@ -0,0 +1,68 @@
/* zebra_mroute code
* Copyright (C) 2016 Cumulus Networks, Inc.
* Donald Sharp
*
* This file is part of Quagga
*
* Quagga is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* Quagga is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Zebra; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <zebra.h>
#include "stream.h"
#include "prefix.h"
#include "vrf.h"
#include "rib.h"
#include "zebra/zserv.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_mroute.h"
#include "zebra/rt.h"
int
zebra_ipmr_route_stats (struct zserv *client, int fd, u_short length, struct zebra_vrf *zvrf)
{
struct mcast_route_data mroute;
struct stream *s;
int suc;
char sbuf[40];
char gbuf[40];
memset (&mroute, 0, sizeof (mroute));
stream_get (&mroute.sg.src, client->ibuf, 4);
stream_get (&mroute.sg.grp, client->ibuf, 4);
mroute.ifindex = stream_getl (client->ibuf);
strcpy (sbuf, inet_ntoa (mroute.sg.src));
strcpy (gbuf, inet_ntoa (mroute.sg.grp));
suc = kernel_get_ipmr_sg_stats (&mroute);
s = client->obuf;
stream_reset (s);
zserv_create_header (s, ZEBRA_IPMR_ROUTE_STATS, zvrf_id (zvrf));
stream_put_in_addr (s, &mroute.sg.src);
stream_put_in_addr (s, &mroute.sg.grp);
stream_put (s, &mroute.lastused, sizeof (mroute.lastused));
stream_putl (s, suc);
stream_putw_at (s, 0, stream_get_endp (s));
zebra_server_send_message (client);
return 0;
}

35
zebra/zebra_mroute.h Normal file
View File

@ -0,0 +1,35 @@
/* zebra_mroute.h
* Copyright (C) 2016 Cumulus Networks, Inc.
* Donald Sharp
*
* This file is part of Quagga.
*
* Quagga is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* Quagga is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Zebra; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef __ZEBRA_MROUTE_H__
#define __ZEBRA_MROUTE_H__
struct mcast_route_data {
struct prefix_sg sg;
unsigned int ifindex;
unsigned long long lastused;
};
int zebra_ipmr_route_stats (struct zserv *client, int sock, u_short length, struct zebra_vrf *zvf);
#endif

View File

@ -54,6 +54,7 @@
#include "zebra/rtadv.h" #include "zebra/rtadv.h"
#include "zebra/zebra_mpls.h" #include "zebra/zebra_mpls.h"
#include "zebra/zebra_fpm.h" #include "zebra/zebra_fpm.h"
#include "zebra/zebra_mroute.h"
/* Event list of zebra. */ /* Event list of zebra. */
enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE }; enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE };
@ -785,8 +786,6 @@ zsend_write_nexthop (struct stream *s, struct nexthop *nexthop)
switch (nexthop->type) switch (nexthop->type)
{ {
case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4:
stream_put_in_addr (s, &nexthop->gate.ipv4);
break;
case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4_IFINDEX:
stream_put_in_addr (s, &nexthop->gate.ipv4); stream_put_in_addr (s, &nexthop->gate.ipv4);
stream_putl (s, nexthop->ifindex); stream_putl (s, nexthop->ifindex);
@ -2051,6 +2050,9 @@ zebra_client_read (struct thread *thread)
case ZEBRA_MPLS_LABELS_DELETE: case ZEBRA_MPLS_LABELS_DELETE:
zread_mpls_labels (command, client, length, vrf_id); zread_mpls_labels (command, client, length, vrf_id);
break; break;
case ZEBRA_IPMR_ROUTE_STATS:
zebra_ipmr_route_stats (client, sock, length, zvrf);
break;
default: default:
zlog_info ("Zebra received unknown command %d", command); zlog_info ("Zebra received unknown command %d", command);
break; break;