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,
struct bgp_nlri *mp_update)
{
afi_t pkt_afi, afi;
iana_afi_t pkt_afi;
afi_t afi;
safi_t pkt_safi, safi;
bgp_size_t nlri_len;
size_t start;
@ -2000,7 +2001,8 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
struct bgp_nlri *mp_withdraw)
{
struct stream *s;
afi_t pkt_afi, afi;
iana_afi_t pkt_afi;
afi_t afi;
safi_t pkt_safi, safi;
u_int16_t withdraw_len;
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)
{
size_t sizep;
afi_t pkt_afi;
iana_afi_t pkt_afi;
safi_t pkt_safi;
/* 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)
{
unsigned long attrlen_pnt;
afi_t pkt_afi;
iana_afi_t pkt_afi;
safi_t pkt_safi;
/* 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 stream *s = BGP_INPUT (peer);
afi_t afi;
safi_t safi;
/* Verify length is 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);
/* 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;
/* 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])
peer->afc_nego[mpc.afi][mpc.safi] = 1;
if (peer->afc[afi][safi])
peer->afc_nego[afi][safi] = 1;
else
return -1;
@ -219,7 +221,7 @@ bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
}
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)
{
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 capability_orf_entry entry;
afi_t pkt_afi, afi;
iana_afi_t pkt_afi;
afi_t afi;
safi_t pkt_safi, safi;
u_char type;
u_char mode;
@ -274,7 +277,7 @@ bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)
return 0;
}
entry.mpc.afi = afi;
entry.mpc.afi = pkt_afi;
entry.mpc.safi = safi;
/* validate number field */
@ -418,7 +421,7 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)
{
afi_t afi;
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);
u_char flag = stream_getc (s);
@ -496,7 +499,7 @@ bgp_capability_addpath (struct peer *peer, struct capability_header *hdr)
{
afi_t afi;
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);
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)
{
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);
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))
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 numberp;
int number_of_orfs = 0;
afi_t pkt_afi;
iana_afi_t pkt_afi;
safi_t pkt_safi;
/* Convert AFI, SAFI to values for packet. */
@ -1225,7 +1230,8 @@ bgp_open_capability (struct stream *s, struct peer *peer)
{
u_char len;
unsigned long cp, capp, rcapp;
afi_t afi, pkt_afi;
iana_afi_t pkt_afi;
afi_t afi;
safi_t safi, pkt_safi;
as_t local_as;
u_int32_t restart_time;

View File

@ -31,7 +31,7 @@ struct capability_header
/* Generic MP capability data */
struct capability_mp_data
{
afi_t afi;
iana_afi_t afi;
u_char reserved;
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)
{
struct stream *s;
afi_t pkt_afi;
iana_afi_t pkt_afi;
safi_t pkt_safi;
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 bgp_filter *filter;
int orf_refresh = 0;
afi_t pkt_afi;
iana_afi_t pkt_afi;
safi_t pkt_safi;
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)
{
struct stream *s;
afi_t pkt_afi;
iana_afi_t pkt_afi;
safi_t pkt_safi;
/* Convert AFI, SAFI to values for packet. */
@ -1711,7 +1711,8 @@ bgp_keepalive_receive (struct peer *peer, bgp_size_t size)
static void
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;
struct stream *s;
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_header *hdr;
u_char action;
afi_t pkt_afi, afi;
iana_afi_t pkt_afi;
afi_t afi;
safi_t pkt_safi, safi;
end = pnt + length;

View File

@ -2111,10 +2111,10 @@ bgp_maximum_prefix_restart_timer (struct thread *thread)
}
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)
{
afi_t pkt_afi;
iana_afi_t pkt_afi;
safi_t pkt_safi;
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
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)
{
/* 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
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
* 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
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);
extern int
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_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_IPV6_NEXTHOP_ADD),
DESC_ENTRY (ZEBRA_IPV6_NEXTHOP_DELETE),
DESC_ENTRY (ZEBRA_IPMR_ROUTE_STATS),
};
#undef DESC_ENTRY

View File

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

View File

@ -405,6 +405,7 @@ typedef enum {
ZEBRA_IPV4_NEXTHOP_DELETE,
ZEBRA_IPV6_NEXTHOP_ADD,
ZEBRA_IPV6_NEXTHOP_DELETE,
ZEBRA_IPMR_ROUTE_STATS,
} zebra_message_types_t;
/* Marker value used in new Zserv, in the byte location corresponding
@ -477,6 +478,12 @@ typedef enum {
#define SAFI_RESERVED_5 5
#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
* 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.
* Note: Only useful (i.e., supported) values are defined below.
*/
#define IANA_AFI_RESERVED 0
#define IANA_AFI_IPV4 1
#define IANA_AFI_IPV6 2
#define IANA_AFI_L2VPN 25
#define IANA_AFI_IPMR 128
#define IANA_AFI_IP6MR 129
typedef enum {
IANA_AFI_RESERVED = 0,
IANA_AFI_IPV4 = 1,
IANA_AFI_IPV6 = 2,
IANA_AFI_L2VPN = 25,
IANA_AFI_IPMR = 128,
IANA_AFI_IP6MR = 129
} iana_afi_t;
#define IANA_SAFI_RESERVED 0
#define IANA_SAFI_UNICAST 1
@ -531,7 +540,7 @@ typedef uint32_t route_tag_t;
#define ROUTE_TAG_MAX UINT32_MAX
#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)
return AFI_IP;
@ -540,7 +549,7 @@ static inline afi_t afi_iana2int (afi_t afi)
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)
return IANA_AFI_IPV4;

View File

@ -19,7 +19,6 @@
# 330, Boston, MA 02111-1307, USA.
# 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_REPORT_RECV_IFINDEX_MISMATCH: Report sock/recv ifindex mismatch
# PIM_ENFORCE_LOOPFREE_MFC: Refuse adding looping MFC entries
@ -27,9 +26,8 @@
PIM_DEFS =
#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_ZCLIENT_DEBUG
PIM_DEFS += -DPIM_ENFORCE_LOOPFREE_MFC
#PIM_DEFS += -DPIM_UNEXPECTED_KERNEL_UPCALL
@ -47,24 +45,26 @@ noinst_PROGRAMS = test_igmpv3_join
libpim_a_SOURCES = \
pim_memory.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_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_msg.c pim_upstream.c pim_rpf.c pim_macro.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 = \
pim_memory.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_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_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_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 = \
pim_main.c $(libpim_a_SOURCES)

View File

@ -1,18 +1,17 @@
INTRODUCTION
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
Multicast) mode as defined in section 4.8.2 (PIM-SSM-Only
Routers) of RFC 4601.
qpimd implements PIM-SM (Sparse Mode) of RFC 4601.
Additionally MSDP has been implemented.
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
qpimd - pimd for quagga
qpimd - pimd for FRR
Copyright (C) 2008 Everton da Silva Marques
qpimd is free software; you can redistribute it and/or modify
@ -34,78 +33,16 @@ HOME SITE
qpimd lives at:
https://github.com/udhos/qpimd
https://github.com/freerangerouting/frr
PLATFORMS
qpimd has been tested with Debian Lenny under Linux 2.6.
qpimd has been tested with Debian Jessie.
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
@ -120,7 +57,7 @@ SUPPORT
Please post comments, questions, patches, bug reports at the
support site:
https://github.com/udhos/qpimd
https://freerangerouting/frr
RELATED WORK

View File

@ -54,31 +54,23 @@ void pim_ifassert_winner_set(struct pim_ifchannel *ch,
if (PIM_DEBUG_PIM_EVENTS) {
if (ch->ifassert_state != new_state) {
char src_str[100];
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) assert state changed from %s to %s on interface %s",
__PRETTY_FUNCTION__,
src_str, grp_str,
pim_ifchannel_ifassert_name(ch->ifassert_state),
pim_ifchannel_ifassert_name(new_state),
ch->interface->name);
zlog_debug("%s: (S,G)=%s assert state changed from %s to %s on interface %s",
__PRETTY_FUNCTION__,
ch->sg_str,
pim_ifchannel_ifassert_name(ch->ifassert_state),
pim_ifchannel_ifassert_name(new_state),
ch->interface->name);
}
if (winner_changed) {
char src_str[100];
char grp_str[100];
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));
char was_str[INET_ADDRSTRLEN];
char winner_str[INET_ADDRSTRLEN];
pim_inet4_dump("<was?>", ch->ifassert_winner, was_str, sizeof(was_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",
__PRETTY_FUNCTION__,
src_str, grp_str,
was_str, winner_str, ch->interface->name);
zlog_debug("%s: (S,G)=%s assert winner changed from %s to %s on interface %s",
__PRETTY_FUNCTION__,
ch->sg_str,
was_str, winner_str, ch->interface->name);
}
} /* PIM_DEBUG_PIM_EVENTS */
@ -98,7 +90,7 @@ static void on_trace(const char *label,
struct interface *ifp, struct in_addr src)
{
if (PIM_DEBUG_PIM_TRACE) {
char src_str[100];
char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
zlog_debug("%s: from %s on %s",
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 (assert_action_a1(ch)) {
char src_str[100];
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",
zlog_warn("%s: %s: (S,G)=%s assert_action_a1 failure on interface %s",
__PRETTY_FUNCTION__, caller,
src_str, grp_str, ch->interface->name);
ch->sg_str, ch->interface->name);
/* log warning only */
}
}
@ -156,16 +144,16 @@ static int dispatch_assert(struct interface *ifp,
struct pim_assert_metric recv_metric)
{
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) {
char source_str[100];
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",
zlog_warn("%s: (S,G)=%s failure creating channel on interface %s",
__PRETTY_FUNCTION__,
source_str, group_str, ifp->name);
pim_str_sg_dump (&sg), ifp->name);
return -1;
}
@ -193,7 +181,6 @@ static int dispatch_assert(struct interface *ifp,
}
else {
if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
assert_action_a3(ch);
}
}
@ -222,13 +209,9 @@ static int dispatch_assert(struct interface *ifp,
break;
default:
{
char source_str[100];
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",
zlog_warn("%s: (S,G)=%s invalid assert state %d on interface %s",
__PRETTY_FUNCTION__,
source_str, group_str, ch->ifassert_state, ifp->name);
ch->sg_str, ch->ifassert_state, ifp->name);
}
return -2;
}
@ -241,7 +224,7 @@ int pim_assert_recv(struct interface *ifp,
struct in_addr src_addr,
uint8_t *buf, int buf_size)
{
struct prefix msg_group_addr;
struct prefix_sg sg;
struct prefix msg_source_addr;
struct pim_assert_metric msg_metric;
int offset;
@ -256,9 +239,10 @@ int pim_assert_recv(struct interface *ifp,
/*
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) {
char src_str[100];
char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s",
__PRETTY_FUNCTION__,
@ -273,7 +257,7 @@ int pim_assert_recv(struct interface *ifp,
*/
offset = pim_parse_addr_ucast (&msg_source_addr, curr, curr_size);
if (offset < 1) {
char src_str[100];
char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
__PRETTY_FUNCTION__,
@ -284,7 +268,7 @@ int pim_assert_recv(struct interface *ifp,
curr_size -= offset;
if (curr_size != 8) {
char src_str[100];
char src_str[INET_ADDRSTRLEN];
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",
__PRETTY_FUNCTION__,
@ -311,12 +295,12 @@ int pim_assert_recv(struct interface *ifp,
msg_metric.route_metric = pim_read_uint32_host(curr);
if (PIM_DEBUG_PIM_TRACE) {
char neigh_str[100];
char source_str[100];
char group_str[100];
char neigh_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
char group_str[INET_ADDRSTRLEN];
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("<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",
__PRETTY_FUNCTION__, neigh_str, ifp->name,
source_str, group_str,
@ -329,7 +313,7 @@ int pim_assert_recv(struct interface *ifp,
return dispatch_assert(ifp,
msg_source_addr.u.prefix4,
msg_group_addr.u.prefix4,
sg.grp,
msg_metric);
}
@ -399,7 +383,7 @@ int pim_assert_build_msg(uint8_t *pim_msg, int buf_size,
remain,
group_addr);
if (!pim_msg_curr) {
char group_str[100];
char group_str[INET_ADDRSTRLEN];
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);
@ -412,7 +396,7 @@ int pim_assert_build_msg(uint8_t *pim_msg, int buf_size,
remain,
source_addr);
if (!pim_msg_curr) {
char source_str[100];
char source_str[INET_ADDRSTRLEN];
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);
@ -448,17 +432,23 @@ static int pim_assert_do(struct pim_ifchannel *ch,
int pim_msg_size;
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;
if (!pim_ifp) {
zlog_warn("%s: pim not enabled on interface: %s",
__PRETTY_FUNCTION__, ifp->name);
if (PIM_DEBUG_PIM_TRACE)
zlog_debug("%s: channel %s pim not enabled on interface: %s",
__PRETTY_FUNCTION__, ch->sg_str, ifp->name);
return -1;
}
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.route_metric,
metric.rpt_bit_flag);
@ -480,19 +470,16 @@ static int pim_assert_do(struct pim_ifchannel *ch,
pim_hello_require(ifp);
if (PIM_DEBUG_PIM_TRACE) {
char source_str[100];
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",
zlog_debug("%s: to %s: (S,G)=%s pref=%u metric=%u rpt_bit=%u",
__PRETTY_FUNCTION__,
ifp->name, source_str, group_str,
ifp->name, ch->sg_str,
metric.metric_preference,
metric.route_metric,
PIM_FORCE_BOOLEAN(metric.rpt_bit_flag));
}
if (pim_msg_send(pim_ifp->pim_sock_fd,
pim_ifp->primary_address,
qpim_all_pim_routers_addr,
pim_msg,
pim_msg_size,
@ -523,7 +510,7 @@ static int pim_assert_cancel(struct pim_ifchannel *ch)
metric.rpt_bit_flag = 0;
metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_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);
}
@ -533,28 +520,20 @@ static int on_assert_timer(struct thread *t)
struct pim_ifchannel *ch;
struct interface *ifp;
zassert(t);
ch = THREAD_ARG(t);
zassert(ch);
ifp = ch->interface;
zassert(ifp);
if (PIM_DEBUG_PIM_TRACE) {
char src_str[100];
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",
zlog_debug("%s: (S,G)=%s timer expired on interface %s",
__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) {
case PIM_IFASSERT_I_AM_WINNER:
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
assert_action_a3(ch);
break;
case PIM_IFASSERT_I_AM_LOSER:
@ -562,13 +541,10 @@ static int on_assert_timer(struct thread *t)
break;
default:
{
char source_str[100];
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_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s",
__PRETTY_FUNCTION__,
source_str, group_str, ch->ifassert_state, ifp->name);
if (PIM_DEBUG_PIM_EVENTS)
zlog_warn("%s: (S,G)=%s invalid assert state %d on interface %s",
__PRETTY_FUNCTION__,
ch->sg_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)
{
struct interface *ifp;
zassert(ch);
ifp = ch->interface;
zassert(ifp);
if (PIM_DEBUG_PIM_TRACE) {
if (ch->t_ifassert_timer) {
char src_str[100];
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",
zlog_debug("%s: (S,G)=%s cancelling timer on interface %s",
__PRETTY_FUNCTION__,
src_str, grp_str, ifp->name);
ch->sg_str, ch->interface->name);
}
}
THREAD_OFF(ch->t_ifassert_timer);
zassert(!ch->t_ifassert_timer);
}
static void pim_assert_timer_set(struct pim_ifchannel *ch,
int interval)
{
struct interface *ifp;
zassert(ch);
ifp = ch->interface;
zassert(ifp);
assert_timer_off(ch);
if (PIM_DEBUG_PIM_TRACE) {
char src_str[100];
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",
zlog_debug("%s: (S,G)=%s starting %u sec timer on interface %s",
__PRETTY_FUNCTION__,
src_str, grp_str, interval, ifp->name);
ch->sg_str, interval, ch->interface->name);
}
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 pim_interface *pim_ifp;
zassert(ifp);
pim_ifp = ifp->info;
if (!pim_ifp) {
char src_str[100];
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",
zlog_warn("%s: (S,G)=%s multicast not enabled on interface %s",
__PRETTY_FUNCTION__,
src_str, grp_str, ifp->name);
ch->sg_str, ifp->name);
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_ifp->primary_address));
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
if (assert_action_a3(ch)) {
char src_str[100];
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",
zlog_warn("%s: (S,G)=%s assert_action_a3 failure on interface %s",
__PRETTY_FUNCTION__,
src_str, grp_str, ifp->name);
ch->sg_str, ifp->name);
/* 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;
}
@ -699,7 +648,12 @@ static void assert_action_a2(struct pim_ifchannel *ch,
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)
{
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);
if (pim_assert_send(ch)) {
char src_str[100];
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",
zlog_warn("%s: (S,G)=%s failure sending assert on interface %s",
__PRETTY_FUNCTION__,
src_str, grp_str, ch->interface->name);
ch->sg_str, ch->interface->name);
return -1;
}
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
return 0;
}
@ -746,19 +699,20 @@ static int assert_action_a3(struct pim_ifchannel *ch)
void assert_action_a4(struct pim_ifchannel *ch)
{
if (pim_assert_cancel(ch)) {
char src_str[100];
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",
zlog_warn("%s: failure sending AssertCancel%s on interface %s",
__PRETTY_FUNCTION__,
src_str, grp_str, ch->interface->name);
ch->sg_str, ch->interface->name);
/* log warning only */
}
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)
{
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)
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"
struct pim_br {
struct in_addr source;
struct in_addr group;
struct prefix_sg sg;
struct in_addr pmbr;
};
@ -40,14 +39,14 @@ struct in_addr pim_br_unknown = { .s_addr = 0 };
static struct list *pim_br_list = NULL;
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 pim_br *pim_br;
for (ALL_LIST_ELEMENTS_RO (pim_br_list, node, pim_br)) {
if (source.s_addr == pim_br->source.s_addr &&
group.s_addr == pim_br->group.s_addr)
if (sg->src.s_addr == pim_br->sg.src.s_addr &&
sg->grp.s_addr == pim_br->sg.grp.s_addr)
return pim_br->pmbr;
}
@ -55,14 +54,14 @@ pim_br_get_pmbr (struct in_addr source, struct in_addr group)
}
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 pim_br *pim_br;
for (ALL_LIST_ELEMENTS (pim_br_list, node, next, pim_br)) {
if (source.s_addr == pim_br->source.s_addr &&
group.s_addr == pim_br->group.s_addr)
if (sg->src.s_addr == pim_br->sg.src.s_addr &&
sg->grp.s_addr == pim_br->sg.grp.s_addr)
break;
}
@ -73,8 +72,7 @@ pim_br_set_pmbr (struct in_addr source, struct in_addr group, struct in_addr br)
return;
}
pim_br->source = source;
pim_br->group = group;
pim_br->sg = *sg;
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
*/
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 pim_br *pim_br;
for (ALL_LIST_ELEMENTS (pim_br_list, node, next, pim_br)) {
if (source.s_addr == pim_br->source.s_addr &&
group.s_addr == pim_br->group.s_addr)
if (sg->src.s_addr == pim_br->sg.src.s_addr &&
sg->grp.s_addr == pim_br->sg.grp.s_addr)
break;
}

View File

@ -21,10 +21,10 @@
#ifndef 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_clear_pmbr (struct in_addr source, struct in_addr group);
void pim_br_set_pmbr (struct prefix_sg *sg, struct in_addr value);
void pim_br_clear_pmbr (struct prefix_sg *sg);
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_HELLO_PACKETS_STR "PIM Hello 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_SEND_STR "Dump sent 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 MROUTE_STR "IP multicast 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);

View File

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

View File

@ -25,6 +25,8 @@
#include "memory.h"
#include "prefix.h"
#include "vrf.h"
#include "linklist.h"
#include "plist.h"
#include "pimd.h"
#include "pim_iface.h"
@ -38,14 +40,26 @@
#include "pim_sock.h"
#include "pim_time.h"
#include "pim_ssmpingd.h"
#include "pim_rp.h"
struct interface *pim_regiface = NULL;
struct list *pim_ifchannel_list = NULL;
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);
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)
@ -78,15 +92,16 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
zassert(ifp);
zassert(!ifp->info);
pim_ifp = XMALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
pim_ifp = XCALLOC(MTYPE_PIM_INTERFACE, sizeof(*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;
}
pim_ifp->options = 0;
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_query_interval = IGMP_GENERAL_QUERY_INTERVAL;
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)
PIM_IF_DO_IGMP(pim_ifp->options);
#if 0
/* FIXME: Should join? */
PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options);
#endif
pim_ifp->igmp_join_list = 0;
pim_ifp->igmp_socket_list = 0;
pim_ifp->pim_neighbor_list = 0;
pim_ifp->pim_ifchannel_list = 0;
pim_ifp->igmp_join_list = NULL;
pim_ifp->igmp_socket_list = NULL;
pim_ifp->pim_neighbor_list = NULL;
pim_ifp->pim_ifchannel_list = NULL;
pim_ifp->pim_generation_id = 0;
/* 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);
}
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;
@ -164,16 +177,11 @@ void pim_if_delete(struct interface *ifp)
if (pim_ifp->igmp_join_list) {
pim_if_igmp_join_del_all(ifp);
}
zassert(!pim_ifp->igmp_join_list);
zassert(pim_ifp->igmp_socket_list);
zassert(!listcount(pim_ifp->igmp_socket_list));
pim_ifchannel_delete_all (ifp);
igmp_sock_delete_all (ifp);
zassert(pim_ifp->pim_neighbor_list);
zassert(!listcount(pim_ifp->pim_neighbor_list));
zassert(pim_ifp->pim_ifchannel_list);
zassert(!listcount(pim_ifp->pim_ifchannel_list));
pim_neighbor_delete_all (ifp, "Interface removed from configuration");
if (PIM_MROUTE_IS_ENABLED) {
pim_if_del_vif(ifp);
@ -185,7 +193,7 @@ void pim_if_delete(struct interface *ifp)
XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
ifp->info = 0;
ifp->info = NULL;
}
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,
const char *caller)
{
struct pim_interface *pim_ifp;
struct pim_interface *pim_ifp = ifp->info;
struct in_addr new_prim_addr;
int changed;
pim_ifp = ifp->info;
if (!pim_ifp)
return 0;
if (force_prim_as_any)
new_prim_addr = qpim_inaddr_any;
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;
if (PIM_DEBUG_ZEBRA) {
char new_prim_str[100];
char old_prim_str[100];
char new_prim_str[INET_ADDRSTRLEN];
char old_prim_str[INET_ADDRSTRLEN];
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));
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) {
pim_ifp->primary_address = new_prim_addr;
if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
return changed;
}
pim_addr_change(ifp);
}
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)
{
struct pim_interface *pim_ifp;
int changed;
struct pim_interface *pim_ifp = ifp->info;
int changed = 0;
pim_ifp = ifp->info;
if (!pim_ifp)
return;
changed = 1; /* true */
if (PIM_DEBUG_ZEBRA)
zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change",
__PRETTY_FUNCTION__, ifp->name);
if (!changed) {
return;
if (force_prim_as_any) {
/* if primary address is being forced to zero just flush the
* secondary address list */
changed = pim_sec_addr_del_all(pim_ifp);
} else {
/* re-evaluate the secondary address list */
changed = pim_sec_addr_update(ifp);
}
if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
return;
}
pim_addr_change(ifp);
return changed;
}
static void detect_address_change(struct interface *ifp,
int force_prim_as_any,
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);
if (prim_changed) {
/* no need to detect secondary change because
the reaction would be the same */
pim_ifp = ifp->info;
if (!pim_ifp)
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)
@ -406,6 +583,7 @@ void pim_if_addr_add(struct connected *ifc)
if (pim_ifp->mroute_vif_index < 0) {
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 listnode *node;
struct listnode *nextnode;
int v4_addrs = 0;
int v6_addrs = 0;
struct pim_interface *pim_ifp = ifp->info;
/* PIM/IGMP enabled ? */
if (!ifp->info)
if (!pim_ifp)
return;
for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
struct prefix *p = ifc->address;
if (p->family != AF_INET)
continue;
{
v6_addrs++;
continue;
}
v4_addrs++;
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)
@ -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_rp_setup();
pim_i_am_rp_re_evaluate();
}
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 listnode *node;
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)) {
struct prefix *p = ifc->address;
if (p->family != AF_INET)
continue;
{
v6_addrs++;
continue;
}
if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
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;
}
v4_addrs++;
if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
continue;
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;
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
@ -800,9 +1043,9 @@ int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex)
struct interface *ifp;
ifp = if_lookup_by_index_vrf (ifindex, VRF_DEFAULT);
pim_ifp = ifp->info;
if (!pim_ifp)
if (!ifp || !ifp->info)
return -1;
pim_ifp = ifp->info;
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) {
char addr_str[100];
char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s: neighbor not found for address %s on interface %s",
__PRETTY_FUNCTION__,
addr_str, ifp->name);
}
return 0;
return NULL;
}
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);
if (join_fd < 0) {
char group_str[100];
char source_str[100];
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_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",
@ -995,13 +1238,13 @@ static struct igmp_join *igmp_join_new(struct interface *ifp,
return 0;
}
ij = XMALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
ij = XCALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
if (!ij) {
char group_str[100];
char source_str[100];
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_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__,
sizeof(*ij), group_str, source_str, ifp->name);
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);
if (ij) {
char group_str[100];
char source_str[100];
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_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",
@ -1057,8 +1300,8 @@ int pim_if_igmp_join_add(struct interface *ifp,
ij = igmp_join_new(ifp, group_addr, source_addr);
if (!ij) {
char group_str[100];
char source_str[100];
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_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",
@ -1068,8 +1311,8 @@ int pim_if_igmp_join_add(struct interface *ifp,
}
if (PIM_DEBUG_IGMP_EVENTS) {
char group_str[100];
char source_str[100];
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_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",
@ -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);
if (!ij) {
char group_str[100];
char source_str[100];
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_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",
@ -1117,14 +1360,13 @@ int pim_if_igmp_join_del(struct interface *ifp,
}
if (close(ij->sock_fd)) {
int e = errno;
char group_str[100];
char source_str[100];
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_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",
__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 */
}
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);
}
}
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
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
MA 02110-1301 USA
*/
*/
#ifndef PIM_IFACE_H
#define PIM_IFACE_H
@ -58,12 +58,26 @@ enum pim_interface_type {
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 {
enum pim_interface_type itype;
uint32_t options; /* bit vector */
ifindex_t mroute_vif_index;
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_query_interval; /* IGMPv3 secs between 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 list *pim_ifchannel_list;
/*
if default_holdtime is set (>= 0), use it;
otherwise default_holdtime is 3.5 * hello_period
@ -116,6 +131,7 @@ extern struct interface *pim_regiface;
((pim_ifp)->pim_default_holdtime))
void pim_if_init(void);
void pim_if_terminate (void);
struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim);
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_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_del_vif(struct interface *ifp);
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_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 */

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,7 @@
#include <zebra.h>
#include "if.h"
#include "prefix.h"
#include "pim_upstream.h"
@ -35,7 +36,10 @@ enum pim_ifmembership {
enum pim_ifjoin_state {
PIM_IFJOIN_NOINFO,
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 {
@ -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_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
*/
struct pim_ifchannel {
struct in_addr source_addr; /* (S,G) source key */
struct in_addr group_addr; /* (S,G) group key */
struct pim_ifchannel *parent;
struct list *sources;
struct prefix_sg sg;
char sg_str[PIM_SG_LEN];
struct interface *interface; /* backpointer to interface */
uint32_t flags;
@ -98,33 +112,28 @@ struct pim_ifchannel {
void pim_ifchannel_free(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_delete_on_noinfo(struct interface *ifp);
struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp,
struct in_addr source_addr,
struct in_addr group_addr);
struct prefix_sg *sg);
struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
struct in_addr source_addr,
struct in_addr group_addr);
struct prefix_sg *sg, int flags);
void pim_ifchannel_join_add(struct interface *ifp,
struct in_addr neigh_addr,
struct in_addr upstream,
struct in_addr source_addr,
struct in_addr group_addr,
struct prefix_sg *sg,
uint8_t source_flags,
uint16_t holdtime);
void pim_ifchannel_prune(struct interface *ifp,
struct in_addr upstream,
struct in_addr source_addr,
struct in_addr group_addr,
struct prefix_sg *sg,
uint8_t source_flags,
uint16_t holdtime);
void pim_ifchannel_local_membership_add(struct interface *ifp,
struct in_addr source_addr,
struct in_addr group_addr);
struct prefix_sg *sg);
void pim_ifchannel_local_membership_del(struct interface *ifp,
struct in_addr source_addr,
struct in_addr group_addr);
struct prefix_sg *sg);
void pim_ifchannel_ifjoin_switch(const char *caller,
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_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 */

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_GROUP_OFFSET (4)
#define IGMP_V3_GROUP_RECORD_SOURCE_OFFSET (8)
#define IGMP_CHECKSUM_OFFSET (2)
/* RFC 3376: 8.1. Robustness Variable - Default: 2 */
#define IGMP_DEFAULT_ROBUSTNESS_VARIABLE (2)
@ -64,6 +65,8 @@
/* RFC 3376: 8.8. Last Member Query Interval - Default: 10 deciseconds */
#define IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC (10)
#define IGMP_DEFAULT_VERSION (3)
struct igmp_join {
struct in_addr group_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);
void igmp_sock_delete(struct igmp_sock *igmp);
void igmp_sock_free(struct igmp_sock *igmp);
void igmp_sock_delete_all (struct interface *ifp);
int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len);
void pim_igmp_general_query_on(struct igmp_sock *igmp);
@ -151,6 +154,9 @@ struct igmp_group {
since sources have their counters) */
int group_specific_query_retransmit_count;
/* compatibility mode - igmp v1, v2 or v3 */
int igmp_version;
struct in_addr group_addr;
int group_filtermode_isexcl; /* 0=INCLUDE, 1=EXCLUDE */
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 *
source_new (struct igmp_group *group,
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 */

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)
{
if (PIM_DEBUG_IGMP_TRACE) {
char from_str[100];
char group_str[100];
char from_str[INET_ADDRSTRLEN];
char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<from?>", from, from_str, sizeof(from_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)
{
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);
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));
zlog_debug("Resetting group %s timer to GMI=%ld.%03ld sec on %s",
group_str,
@ -158,15 +114,13 @@ static int igmp_source_timer(struct thread *t)
struct igmp_source *source;
struct igmp_group *group;
zassert(t);
source = THREAD_ARG(t);
zassert(source);
group = source->source_group;
if (PIM_DEBUG_IGMP_TRACE) {
char group_str[100];
char source_str[100];
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_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",
@ -176,7 +130,7 @@ static int igmp_source_timer(struct thread *t)
}
zassert(source->t_source_timer);
source->t_source_timer = 0;
source->t_source_timer = NULL;
/*
RFC 3376: 6.3. IGMPv3 Source-Specific Forwarding Rules
@ -230,8 +184,8 @@ static void source_timer_off(struct igmp_group *group,
return;
if (PIM_DEBUG_IGMP_TRACE) {
char group_str[100];
char source_str[100];
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_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",
@ -250,8 +204,8 @@ static void igmp_source_timer_on(struct igmp_group *group,
source_timer_off(group, source);
if (PIM_DEBUG_IGMP_EVENTS) {
char group_str[100];
char source_str[100];
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_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",
@ -291,8 +245,8 @@ void igmp_source_reset_gmi(struct igmp_sock *igmp,
pim_ifp->igmp_query_max_response_time_dsec);
if (PIM_DEBUG_IGMP_TRACE) {
char group_str[100];
char source_str[100];
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_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) {
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;
if (PIM_DEBUG_IGMP_TRACE) {
char group_str[100];
char source_str[100];
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_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",
@ -413,8 +367,8 @@ void igmp_source_delete(struct igmp_source *source)
/* sanity check that forwarding has been disabled */
if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
char group_str[100];
char source_str[100];
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_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",
@ -483,8 +437,8 @@ source_new (struct igmp_group *group,
struct igmp_source *src;
if (PIM_DEBUG_IGMP_TRACE) {
char group_str[100];
char source_str[100];
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_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",
@ -493,9 +447,9 @@ source_new (struct igmp_group *group,
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) {
zlog_warn("%s %s: XMALLOC() failure",
zlog_warn("%s %s: XCALLOC() failure",
__FILE__, __PRETTY_FUNCTION__);
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 };
source = igmp_find_source_by_addr (group, star);
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) */
@ -702,7 +658,8 @@ static void isex_incl(struct igmp_group *group,
void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from,
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 igmp_group *group;
@ -716,6 +673,10 @@ void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from,
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) {
/* EXCLUDE mode */
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) */
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) */
for (i = 0; i < num_sources; ++i) {
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)
{
char query_buf[PIM_IGMP_BUFSIZE_WRITE];
struct igmp_sock *igmp;
struct pim_interface *pim_ifp;
long lmqc; /* Last Member Query Count */
long lmqi_msec; /* Last Member Query Interval */
long lmqt_msec; /* Last Member Query Time */
int s_flag;
int query_buf_size;
igmp = group->group_igmp_sock;
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;
lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec;
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;
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));
zlog_debug("retransmit_group_specific_query: group %s on %s: s_flag=%d count=%d",
group_str, igmp->interface->name, s_flag,
@ -1077,18 +1056,19 @@ static void group_retransmit_group(struct igmp_group *group)
interest.
*/
pim_igmp_send_membership_query(group,
igmp->fd,
igmp->interface->name,
query_buf,
sizeof(query_buf),
0 /* num_sources_tosend */,
group->group_addr /* dst_addr */,
group->group_addr /* group_addr */,
pim_ifp->igmp_specific_query_max_response_time_dsec,
s_flag,
igmp->querier_robustness_variable,
igmp->querier_query_interval);
igmp_send_query(pim_ifp->igmp_version,
group,
igmp->fd,
igmp->interface->name,
query_buf,
sizeof(query_buf),
0 /* num_sources_tosend */,
group->group_addr /* dst_addr */,
group->group_addr /* group_addr */,
pim_ifp->igmp_specific_query_max_response_time_dsec,
s_flag,
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;
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_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);
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));
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,
@ -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;
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));
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,
@ -1198,19 +1175,19 @@ static int group_retransmit_sources(struct igmp_group *group,
interest.
*/
pim_igmp_send_membership_query(group,
igmp->fd,
igmp->interface->name,
query_buf1,
sizeof(query_buf1),
num_sources_tosend1,
group->group_addr,
group->group_addr,
pim_ifp->igmp_specific_query_max_response_time_dsec,
1 /* s_flag */,
igmp->querier_robustness_variable,
igmp->querier_query_interval);
igmp_send_query(pim_ifp->igmp_version,
group,
igmp->fd,
igmp->interface->name,
query_buf1,
sizeof(query_buf1),
num_sources_tosend1,
group->group_addr,
group->group_addr,
pim_ifp->igmp_specific_query_max_response_time_dsec,
1 /* s_flag */,
igmp->querier_robustness_variable,
igmp->querier_query_interval);
}
} /* 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;
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));
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,
@ -1240,19 +1217,19 @@ static int group_retransmit_sources(struct igmp_group *group,
interest.
*/
pim_igmp_send_membership_query(group,
igmp->fd,
igmp->interface->name,
query_buf2,
sizeof(query_buf2),
num_sources_tosend2,
group->group_addr,
group->group_addr,
pim_ifp->igmp_specific_query_max_response_time_dsec,
0 /* s_flag */,
igmp->querier_robustness_variable,
igmp->querier_query_interval);
igmp_send_query(pim_ifp->igmp_version,
group,
igmp->fd,
igmp->interface->name,
query_buf2,
sizeof(query_buf2),
num_sources_tosend2,
group->group_addr,
group->group_addr,
pim_ifp->igmp_specific_query_max_response_time_dsec,
0 /* s_flag */,
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 send_with_sflag_set; /* boolean */
zassert(t);
group = THREAD_ARG(t);
zassert(group);
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));
zlog_debug("group_retransmit_timer: group %s on %s",
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,
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
@ -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;
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));
zlog_debug("Scheduling %ld.%03ld sec retransmit timer for group %s on %s",
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 */
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));
zlog_debug("%s: group %s on %s: LMQC=%d LMQI=%d dsec LMQT=%d msec",
__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 */
if (PIM_DEBUG_IGMP_TRACE) {
char group_str[100];
char source_str[100];
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_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",
@ -1613,32 +1588,19 @@ void igmp_source_timer_lower_to_lmqt(struct igmp_source *source)
igmp_source_timer_on(group, source, lmqt_msec);
}
/*
Copy sources to message:
struct in_addr *sources = (struct in_addr *)(query_buf + IGMP_V3_SOURCES_OFFSET);
if (num_sources > 0) {
struct listnode *node;
struct igmp_source *src;
int i = 0;
for (ALL_LIST_ELEMENTS_RO(source_list, node, src)) {
sources[i++] = src->source_addr;
}
}
*/
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)
void
igmp_v3_send_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;
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[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));
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);
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) {
char dst_str[100];
char group_str[100];
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("%s: to %s on %s: group=%s sources=%d msg_size=%zd s_flag=%x QRV=%u QQI=%u QQIC=%02x checksum=%x",
__PRETTY_FUNCTION__,
dst_str, ifname, group_str, num_sources,
msg_size, s_flag, querier_robustness_variable,
querier_query_interval, qqic, checksum);
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",
dst_str, ifname, group_str,
num_sources, msg_size, s_flag, querier_robustness_variable,
querier_query_interval, qqic);
}
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,
(struct sockaddr *)&to, tolen);
if (sent != (ssize_t) msg_size) {
int e = errno;
char dst_str[100];
char group_str[100];
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("%s: sendto() failure to %s on %s: group=%s msg_size=%zd: errno=%d: %s",
__PRETTY_FUNCTION__,
dst_str, ifname, group_str, msg_size,
e, safe_strerror(e));
zlog_warn("Send IGMPv3 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("%s: sendto() partial to %s on %s: group=%s msg_size=%zd: sent=%zd",
__PRETTY_FUNCTION__,
dst_str, ifname, group_str,
msg_size, sent);
zlog_warn("Send IGMPv3 query failed due to %s on %s: group=%s msg_size=%zd: sent=%zd",
dst_str, ifname, group_str, msg_size, sent);
}
return;
}
@ -1742,8 +1698,8 @@ void pim_igmp_send_membership_query(struct igmp_group *group,
if (!s_flag) {
/* general query? */
if (PIM_INADDR_IS_ANY(group_addr)) {
char dst_str[100];
char group_str[100];
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_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);
}
}
}
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_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 */
#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_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,
struct in_addr group_addr,
int num_sources, struct in_addr *sources);
void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from,
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,
struct in_addr group_addr,
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 in_addr src_addr);
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);
void igmp_v3_send_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);
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 */

View File

@ -23,6 +23,8 @@
#include "log.h"
#include "prefix.h"
#include "if.h"
#include "vty.h"
#include "plist.h"
#include "pimd.h"
#include "pim_str.h"
@ -30,15 +32,19 @@
#include "pim_msg.h"
#include "pim_pim.h"
#include "pim_join.h"
#include "pim_oil.h"
#include "pim_iface.h"
#include "pim_hello.h"
#include "pim_ifchannel.h"
#include "pim_rpf.h"
#include "pim_rp.h"
static void on_trace(const char *label,
struct interface *ifp, struct in_addr src)
static void
on_trace (const char *label,
struct interface *ifp, struct in_addr src)
{
if (PIM_DEBUG_PIM_TRACE) {
char src_str[100];
char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
zlog_debug("%s: from %s on %s",
label, src_str, ifp->name);
@ -49,58 +55,81 @@ static void recv_join(struct interface *ifp,
struct pim_neighbor *neigh,
uint16_t holdtime,
struct in_addr upstream,
struct in_addr group,
struct in_addr source,
struct prefix_sg *sg,
uint8_t source_flags)
{
if (PIM_DEBUG_PIM_TRACE) {
char up_str[100];
char src_str[100];
char grp_str[100];
char neigh_str[100];
char up_str[INET_ADDRSTRLEN];
char neigh_str[INET_ADDRSTRLEN];
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));
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__,
src_str, grp_str,
pim_str_sg_dump (sg),
source_flags & PIM_RPT_BIT_MASK,
source_flags & PIM_WILDCARD_BIT_MASK,
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 */
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,
struct pim_neighbor *neigh,
uint16_t holdtime,
struct in_addr upstream,
struct in_addr group,
struct in_addr source,
struct prefix_sg *sg,
uint8_t source_flags)
{
if (PIM_DEBUG_PIM_TRACE) {
char up_str[100];
char src_str[100];
char grp_str[100];
char neigh_str[100];
char up_str[INET_ADDRSTRLEN];
char neigh_str[INET_ADDRSTRLEN];
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));
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__,
src_str, grp_str,
pim_str_sg_dump (sg),
source_flags & PIM_RPT_BIT_MASK,
source_flags & PIM_WILDCARD_BIT_MASK,
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,
@ -117,8 +146,6 @@ int pim_joinprune_recv(struct interface *ifp,
int remain;
int group;
on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
buf = tlv_buf;
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,
buf, pastend - buf);
if (addr_offset < 1) {
char src_str[100];
char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
__PRETTY_FUNCTION__,
@ -141,8 +168,8 @@ int pim_joinprune_recv(struct interface *ifp,
Check upstream address family
*/
if (msg_upstream_addr.family != AF_INET) {
if (PIM_DEBUG_PIM_TRACE) {
char src_str[100];
if (PIM_DEBUG_PIM_J_P) {
char src_str[INET_ADDRSTRLEN];
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",
__PRETTY_FUNCTION__,
@ -153,7 +180,7 @@ int pim_joinprune_recv(struct interface *ifp,
remain = pastend - buf;
if (remain < 4) {
char src_str[100];
char src_str[INET_ADDRSTRLEN];
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",
__PRETTY_FUNCTION__,
@ -168,28 +195,29 @@ int pim_joinprune_recv(struct interface *ifp,
++buf;
++buf;
if (PIM_DEBUG_PIM_TRACE) {
char src_str[100];
char upstream_str[100];
if (PIM_DEBUG_PIM_J_P) {
char src_str[INET_ADDRSTRLEN];
char upstream_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
upstream_str, sizeof(upstream_str));
zlog_warn("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s",
__PRETTY_FUNCTION__,
upstream_str, msg_num_groups, msg_holdtime,
src_str, ifp->name);
zlog_debug ("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s",
__PRETTY_FUNCTION__,
upstream_str, msg_num_groups, msg_holdtime,
src_str, ifp->name);
}
/* Scan groups */
for (group = 0; group < msg_num_groups; ++group) {
struct prefix msg_group_addr;
struct prefix msg_source_addr;
struct prefix_sg sg;
uint8_t msg_source_flags;
uint16_t msg_num_joined_sources;
uint16_t msg_num_pruned_sources;
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);
if (addr_offset < 1) {
return -5;
@ -198,7 +226,7 @@ int pim_joinprune_recv(struct interface *ifp,
remain = pastend - buf;
if (remain < 4) {
char src_str[100];
char src_str[INET_ADDRSTRLEN];
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",
__PRETTY_FUNCTION__,
@ -211,25 +239,25 @@ int pim_joinprune_recv(struct interface *ifp,
msg_num_pruned_sources = ntohs(*(const uint16_t *) buf);
buf += 2;
if (PIM_DEBUG_PIM_TRACE) {
char src_str[100];
char upstream_str[100];
char group_str[100];
if (PIM_DEBUG_PIM_J_P) {
char src_str[INET_ADDRSTRLEN];
char upstream_str[INET_ADDRSTRLEN];
char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
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));
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__,
upstream_str, group_str, msg_group_addr.prefixlen,
upstream_str, group_str,
msg_num_joined_sources, msg_num_pruned_sources,
src_str, ifp->name);
}
/* Scan joined sources */
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,
buf, pastend - buf);
if (addr_offset < 1) {
@ -240,14 +268,20 @@ int pim_joinprune_recv(struct interface *ifp,
recv_join(ifp, neigh, msg_holdtime,
msg_upstream_addr.u.prefix4,
msg_group_addr.u.prefix4,
msg_source_addr.u.prefix4,
&sg,
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 */
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,
buf, pastend - buf);
if (addr_offset < 1) {
@ -258,11 +292,12 @@ int pim_joinprune_recv(struct interface *ifp,
recv_prune(ifp, neigh, msg_holdtime,
msg_upstream_addr.u.prefix4,
msg_group_addr.u.prefix4,
msg_source_addr.u.prefix4,
&sg,
msg_source_flags);
}
if (ch)
pim_ifchannel_set_star_g_join_state (ch, 1);
ch = NULL;
} /* scan groups */
return 0;
@ -270,16 +305,14 @@ int pim_joinprune_recv(struct interface *ifp,
int pim_joinprune_send(struct interface *ifp,
struct in_addr upstream_addr,
struct in_addr source_addr,
struct in_addr group_addr,
struct pim_upstream *up,
int send_join)
{
struct pim_interface *pim_ifp;
uint8_t pim_msg[1000];
const uint8_t *pastend = pim_msg + sizeof(pim_msg);
uint8_t *pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* room for pim header */
uint8_t pim_msg[9000];
int pim_msg_size;
int remain;
on_trace (__PRETTY_FUNCTION__, ifp, upstream_addr);
zassert(ifp);
@ -292,31 +325,23 @@ int pim_joinprune_send(struct interface *ifp,
return -1;
}
if (PIM_DEBUG_PIM_TRACE) {
char source_str[100];
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));
if (PIM_DEBUG_PIM_J_P) {
char dst_str[INET_ADDRSTRLEN];
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__,
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_DEBUG_PIM_TRACE) {
char source_str[100];
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));
if (PIM_DEBUG_PIM_J_P) {
char dst_str[INET_ADDRSTRLEN];
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__,
send_join ? "Join" : "Prune",
source_str, group_str, dst_str, ifp->name);
up->sg_str, dst_str, ifp->name);
}
return 0;
}
@ -335,83 +360,14 @@ int pim_joinprune_send(struct interface *ifp,
/*
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;
pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr,
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_size < 0)
return pim_msg_size;
if (pim_msg_send(pim_ifp->pim_sock_fd,
pim_ifp->primary_address,
qpim_all_pim_routers_addr,
pim_msg,
pim_msg_size,

View File

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

View File

@ -21,22 +21,39 @@
#include <zebra.h>
#include "log.h"
#include "prefix.h"
#include "vty.h"
#include "plist.h"
#include "pim_macro.h"
#include "pimd.h"
#include "pim_str.h"
#include "pim_macro.h"
#include "pim_iface.h"
#include "pim_ifchannel.h"
#include "pim_rp.h"
/*
DownstreamJPState(S,G,I) is the per-interface state machine for
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)
{
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;
if (!ifp) {
char src_str[100];
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",
zlog_warn("%s: (S,G)=%s: null interface",
__PRETTY_FUNCTION__,
src_str, grp_str);
ch->sg_str);
return 0; /* false */
}
@ -116,13 +129,9 @@ int pim_macro_ch_lost_assert(const struct pim_ifchannel *ch)
pim_ifp = ifp->info;
if (!pim_ifp) {
char src_str[100];
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",
zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
__PRETTY_FUNCTION__,
src_str, grp_str, ifp->name);
ch->sg_str, ifp->name);
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;
if (!pim_ifp) {
char src_str[100];
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",
zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
__PRETTY_FUNCTION__,
src_str, grp_str, ch->interface->name);
ch->sg_str, ch->interface->name);
return 0; /* false */
}
@ -225,13 +230,8 @@ int pim_macro_ch_could_assert_eval(const struct pim_ifchannel *ch)
ifp = ch->interface;
if (!ifp) {
char src_str[100];
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__,
src_str, grp_str);
zlog_warn("%s: (S,G)=%s: null interface",
__PRETTY_FUNCTION__, ch->sg_str);
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)
{
if (ch->upstream->join_state != PIM_UPSTREAM_JOINED) {
if (ch->upstream->join_state == PIM_UPSTREAM_NOTJOINED) {
/* oiflist is NULL */
return 0; /* false */
}
@ -386,25 +386,15 @@ int pim_macro_assert_tracking_desired_eval(const struct pim_ifchannel *ch)
ifp = ch->interface;
if (!ifp) {
char src_str[100];
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__,
src_str, grp_str);
zlog_warn("%s: (S,G)=%s: null interface",
__PRETTY_FUNCTION__, ch->sg_str);
return 0; /* false */
}
pim_ifp = ifp->info;
if (!pim_ifp) {
char src_str[100];
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__,
src_str, grp_str, ch->interface->name);
zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
__PRETTY_FUNCTION__, ch->sg_str, ch->interface->name);
return 0; /* false */
}

View File

@ -43,10 +43,9 @@
#include "pim_version.h"
#include "pim_signals.h"
#include "pim_zebra.h"
#ifdef PIM_ZCLIENT_DEBUG
extern int zclient_debug;
#endif
#include "pim_msdp.h"
#include "pim_iface.h"
#include "pim_rp.h"
extern struct host host;
@ -70,6 +69,7 @@ zebra_capabilities_t _caps_p [] =
ZCAP_NET_ADMIN,
ZCAP_SYS_ADMIN,
ZCAP_NET_RAW,
ZCAP_BIND,
};
/* pimd privileges to run with */
@ -104,18 +104,9 @@ Daemon which manages PIM.\n\n\
-A, --vty_addr Set vty's bind address\n\
-P, --vty_port Set vty's port number\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\
\n\
Report bugs to %s\n", progname, PIMD_BUG_ADDRESS);
Report bugs to %s\n", progname, PACKAGE_BUGREPORT);
}
exit (status);
@ -177,11 +168,6 @@ int main(int argc, char** argv, char** envp) {
print_version(progname);
exit (0);
break;
#ifdef PIM_ZCLIENT_DEBUG
case 'Z':
zclient_debug = 1;
break;
#endif
case 'h':
usage (0);
break;
@ -206,8 +192,12 @@ int main(int argc, char** argv, char** envp) {
vrf_init ();
access_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_init();
pim_msdp_init (master);
/*
* Initialize zclient "update" and "lookup" sockets
@ -254,11 +244,6 @@ int main(int argc, char** argv, char** envp) {
PIM_DO_DEBUG_ZEBRA;
#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
zlog_notice("PIM_CHECK_RECV_IFINDEX_SANITY: will match sock/recv ifindex");
#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_STATIC_ROUTE, "PIM Static Route")
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_STATIC_ROUTE)
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 */

View File

@ -23,8 +23,11 @@
#include "privs.h"
#include "if.h"
#include "prefix.h"
#include "vty.h"
#include "plist.h"
#include "pimd.h"
#include "pim_rpf.h"
#include "pim_mroute.h"
#include "pim_oil.h"
#include "pim_str.h"
@ -34,10 +37,14 @@
#include "pim_rp.h"
#include "pim_oil.h"
#include "pim_register.h"
#include "pim_ifchannel.h"
#include "pim_zlookup.h"
/* GLOBAL VARS */
extern struct zebra_privs_t pimd_privs;
static struct thread *qpim_mroute_socket_reader = NULL;
static void mroute_read_on(void);
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 opt = enable ? MRT_INIT : MRT_DONE;
socklen_t opt_len = sizeof(opt);
int rcvbuf = 1024 * 1024 * 8;
long flags;
err = setsockopt(fd, IPPROTO_IP, opt, &opt, opt_len);
if (err) {
int e = errno;
zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
__FILE__, __PRETTY_FUNCTION__,
fd, enable ? "MRT_INIT" : "MRT_DONE", opt, e, safe_strerror(e));
errno = e;
fd, enable ? "MRT_INIT" : "MRT_DONE", opt, errno, safe_strerror(errno));
return -1;
}
#if 0
zlog_info("%s %s: setsockopt(fd=%d,IPPROTO_IP,MRT_INIT,opt=%d): ok",
__FILE__, __PRETTY_FUNCTION__,
fd, opt);
#endif
err = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
if (err) {
zlog_warn("%s: failure: setsockopt(fd=%d, SOL_SOCKET, %d): errno=%d: %s",
__PRETTY_FUNCTION__, fd, rcvbuf, errno, safe_strerror(errno));
}
return 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))
flags = fcntl(fd, F_GETFL, 0);
if (flags < 0)
{
if ((c->address->family == AF_INET) &&
prefix_match (CONNECTED_PREFIX (c), &p))
{
return 1;
}
zlog_warn("Could not get flags on socket fd:%d %d %s",
fd, errno, safe_strerror(errno));
close (fd);
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;
}
static const char *igmpmsgtype2str[IGMPMSG_WHOLEPKT + 1] = {
static const char *igmpmsgtype2str[IGMPMSG_WRVIFWHOLE + 1] = {
"<unknown_upcall?>",
"NOCACHE",
"WRONGVIF",
"WHOLEPKT", };
"WHOLEPKT",
"WRVIFWHOLE" };
static int
pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg,
const char *src_str, const char *grp_str)
pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg)
{
struct pim_interface *pim_ifp = ifp->info;
struct pim_upstream *up;
struct pim_rpf *rpg;
struct prefix_sg sg;
struct channel_oil *oil;
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
* do anything here
*/
if ((rpg->rpf_addr.s_addr == INADDR_NONE) ||
if ((pim_rpf_addr_is_inaddr_none (rpg)) ||
(!pim_ifp) ||
(!(PIM_I_am_DR(pim_ifp))) ||
(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
* 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)
zlog_debug ("%s: Received incoming packet that does originate on our seg",
if (PIM_DEBUG_MROUTE_DETAIL)
zlog_debug ("%s: Received incoming packet that doesn't originate on our seg",
__PRETTY_FUNCTION__);
return 0;
}
if (PIM_DEBUG_PIM_TRACE) {
zlog_debug("%s: Adding a Route for %s from %s for WHOLEPKT consumption",
__PRETTY_FUNCTION__, grp_str, src_str);
memset (&sg, 0, sizeof (struct prefix_sg));
sg.src = msg->im_src;
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 (PIM_DEBUG_PIM_TRACE) {
zlog_debug("%s: Failure to add upstream information for (%s,%s)",
if (PIM_DEBUG_MROUTE) {
zlog_debug("%s: Failure to add upstream information for %s",
__PRETTY_FUNCTION__,
src_str, grp_str);
pim_str_sg_dump (&sg));
}
return 0;
}
pim_upstream_keep_alive_timer_start (up, PIM_KEEPALIVE_PERIOD);
up->channel_oil = pim_channel_oil_add(msg->im_dst,
msg->im_src,
pim_ifp->mroute_vif_index);
if (!up->channel_oil) {
if (PIM_DEBUG_PIM_TRACE) {
zlog_debug("%s: Failure to add channel oil for (%s,%s)",
__PRETTY_FUNCTION__,
src_str, grp_str);
}
return 0;
/*
* I moved this debug till after the actual add because
* I want to take advantage of the up->sg_str being filled in.
*/
if (PIM_DEBUG_MROUTE) {
zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
__PRETTY_FUNCTION__, up->sg_str);
}
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_SOURCE);
PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
up->join_state = PIM_UPSTREAM_JOINED;
return 0;
}
static int
pim_mroute_msg_wholepkt (int fd, struct interface *ifp, const char *buf,
const char *src_str, const char *grp_str)
pim_mroute_msg_wholepkt (int fd, struct interface *ifp, const char *buf)
{
struct pim_interface *pim_ifp;
struct in_addr group;
struct in_addr src;
struct prefix_sg sg;
struct pim_rpf *rpg;
const struct ip *ip_hdr;
struct pim_upstream *up;
ip_hdr = (const struct ip *)buf;
src = ip_hdr->ip_src;
group = ip_hdr->ip_dst;
memset (&sg, 0, sizeof (struct prefix_sg));
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 (PIM_DEBUG_PIM_TRACE) {
zlog_debug("%s: Unable to find upstream channel WHOLEPKT(%s,%s)",
__PRETTY_FUNCTION__, src_str, grp_str);
if (PIM_DEBUG_MROUTE_DETAIL) {
zlog_debug("%s: Unable to find upstream channel WHOLEPKT%s",
__PRETTY_FUNCTION__, pim_str_sg_dump (&sg));
}
return 0;
}
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_I_am_DR(pim_ifp))) ||
(pim_ifp->itype == PIM_INTERFACE_SSM)) {
if (PIM_DEBUG_PIM_TRACE) {
if (PIM_DEBUG_MROUTE) {
zlog_debug("%s: Failed Check send packet", __PRETTY_FUNCTION__);
}
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;
}
static int
pim_mroute_msg_wrongvif (int fd, struct interface *ifp, const struct igmpmsg *msg,
const char *src_str, const char *grp_str)
pim_mroute_msg_wrongvif (int fd, struct interface *ifp, const struct igmpmsg *msg)
{
struct pim_ifchannel *ch;
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.
@ -223,32 +266,39 @@ pim_mroute_msg_wrongvif (int fd, struct interface *ifp, const struct igmpmsg *ms
*/
if (!ifp) {
if (PIM_DEBUG_PIM_TRACE) {
zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) could not find input interface for input_vif_index=%d",
if (PIM_DEBUG_MROUTE)
zlog_debug("%s: WRONGVIF (S,G)=%s could not find input interface for input_vif_index=%d",
__PRETTY_FUNCTION__,
src_str, grp_str, msg->im_vif);
}
pim_str_sg_dump (&sg), msg->im_vif);
return -1;
}
pim_ifp = ifp->info;
if (!pim_ifp) {
if (PIM_DEBUG_PIM_TRACE) {
zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) multicast not enabled on interface %s",
if (PIM_DEBUG_MROUTE)
zlog_debug("%s: WRONGVIF (S,G)=%s multicast not enabled on interface %s",
__PRETTY_FUNCTION__,
src_str, grp_str, ifp->name);
}
pim_str_sg_dump (&sg), ifp->name);
return -2;
}
ch = pim_ifchannel_find(ifp, msg->im_src, msg->im_dst);
ch = pim_ifchannel_find(ifp, &sg);
if (!ch) {
if (PIM_DEBUG_PIM_TRACE) {
zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) could not find channel on interface %s",
struct prefix_sg star_g = sg;
if (PIM_DEBUG_MROUTE)
zlog_debug("%s: WRONGVIF (S,G)=%s could not find channel on interface %s",
__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 (PIM_DEBUG_PIM_TRACE) {
zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) channel is not on Assert NoInfo state for interface %s",
if (PIM_DEBUG_MROUTE) {
zlog_debug("%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
__PRETTY_FUNCTION__,
src_str, grp_str, ifp->name);
ch->sg_str, ifp->name);
}
return -4;
}
if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
if (PIM_DEBUG_PIM_TRACE) {
zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) interface %s is not downstream for channel",
if (PIM_DEBUG_MROUTE) {
zlog_debug("%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
__PRETTY_FUNCTION__,
src_str, grp_str, ifp->name);
ch->sg_str, ifp->name);
}
return -5;
}
if (assert_action_a1(ch)) {
if (PIM_DEBUG_PIM_TRACE) {
zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) assert_action_a1 failure on interface %s",
if (PIM_DEBUG_MROUTE) {
zlog_debug("%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
__PRETTY_FUNCTION__,
src_str, grp_str, ifp->name);
ch->sg_str, ifp->name);
}
return -6;
}
@ -295,107 +345,250 @@ pim_mroute_msg_wrongvif (int fd, struct interface *ifp, const struct igmpmsg *ms
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)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
const struct ip *ip_hdr;
const struct igmpmsg *msg;
char src_str[100] = "<src?>";
char grp_str[100] = "<grp?>";
char ip_src_str[INET_ADDRSTRLEN] = "";
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;
/* kernel upcall must have protocol=0 */
if (ip_hdr->ip_p) {
/* this is not a kernel upcall */
if (PIM_DEBUG_PIM_TRACE) {
if (ip_hdr->ip_p == IPPROTO_IGMP) {
/* We have the IP packet but we do not know which interface this packet was
* 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("<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",
__PRETTY_FUNCTION__, ip_hdr->ip_p, src_str, grp_str, buf_size);
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);
}
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) {
pim_inet4_dump("<src?>", msg->im_src, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", msg->im_dst, grp_str, sizeof(grp_str));
zlog_warn("%s: kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d",
__PRETTY_FUNCTION__,
igmpmsgtype2str[msg->im_msgtype],
msg->im_msgtype,
ip_hdr->ip_p,
fd,
src_str,
grp_str,
ifp ? ifp->name : "<ifname?>",
msg->im_vif);
}
if (!ifp)
return 0;
if (PIM_DEBUG_MROUTE) {
pim_inet4_dump("<src?>", msg->im_src, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", msg->im_dst, grp_str, sizeof(grp_str));
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",
__PRETTY_FUNCTION__,
igmpmsgtype2str[msg->im_msgtype],
msg->im_msgtype,
ip_hdr->ip_p,
fd,
src_str,
grp_str,
ifp->name,
msg->im_vif, buf_size);
}
switch (msg->im_msgtype) {
case IGMPMSG_WRONGVIF:
return pim_mroute_msg_wrongvif(fd, ifp, msg, src_str, grp_str);
break;
case IGMPMSG_NOCACHE:
return pim_mroute_msg_nocache(fd, ifp, msg, src_str, grp_str);
break;
case IGMPMSG_WHOLEPKT:
return pim_mroute_msg_wholepkt(fd, ifp, (const char *)msg, src_str, grp_str);
break;
default:
break;
switch (msg->im_msgtype) {
case IGMPMSG_WRONGVIF:
return pim_mroute_msg_wrongvif(fd, ifp, msg);
break;
case IGMPMSG_NOCACHE:
return pim_mroute_msg_nocache(fd, ifp, msg);
break;
case IGMPMSG_WHOLEPKT:
return pim_mroute_msg_wholepkt(fd, ifp, (const char *)msg);
break;
case IGMPMSG_WRVIFWHOLE:
return pim_mroute_msg_wrvifwhole (fd, ifp, (const char *)msg);
break;
default:
break;
}
}
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 long long count;
char buf[10000];
int result = 0;
int cont = 1;
int fd;
int result;
zassert(t);
zassert(!THREAD_ARG(t));
int rd;
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 */
qpim_mroute_socket_reader = 0;
done:
qpim_mroute_socket_reader = NULL;
mroute_read_on();
return result;
@ -450,8 +643,6 @@ int pim_mroute_socket_enable()
qpim_mroute_socket_creation = pim_time_monotonic_sec();
mroute_read_on();
zassert(PIM_MROUTE_IS_ENABLED);
return 0;
}
@ -475,8 +666,6 @@ int pim_mroute_socket_disable()
mroute_read_off();
qpim_mroute_socket_fd = -1;
zassert(PIM_MROUTE_IS_DISABLED);
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));
if (err) {
char ifaddr_str[100];
int e = errno;
char ifaddr_str[INET_ADDRSTRLEN];
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",
__FILE__, __PRETTY_FUNCTION__,
qpim_mroute_socket_fd, ifp->ifindex, ifaddr_str, flags,
e, safe_strerror(e));
errno = e;
errno, safe_strerror(errno));
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));
if (err) {
int e = errno;
zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
__FILE__, __PRETTY_FUNCTION__,
qpim_mroute_socket_fd, vif_index,
e, safe_strerror(e));
errno = e;
errno, safe_strerror(errno));
return -2;
}
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 orig = 0;
int orig_iif_vif = 0;
qpim_mroute_add_last = pim_time_monotonic_sec();
++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;
}
/*
* 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,
&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)
c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = orig;
if (err) {
int e = errno;
zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
__FILE__, __PRETTY_FUNCTION__,
qpim_mroute_socket_fd,
e, safe_strerror(e));
errno = e;
errno, safe_strerror(errno));
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;
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;
@ -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));
if (err) {
int e = errno;
zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
__FILE__, __PRETTY_FUNCTION__,
qpim_mroute_socket_fd,
e, safe_strerror(e));
errno = e;
if (PIM_DEBUG_MROUTE)
zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
__FILE__, __PRETTY_FUNCTION__,
qpim_mroute_socket_fd,
errno, safe_strerror(errno));
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;
return 0;
@ -643,28 +868,46 @@ pim_mroute_update_counters (struct channel_oil *c_oil)
{
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.oldbytecnt = c_oil->cc.bytecnt;
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))
{
char group_str[100];
char source_str[100];
if (PIM_DEBUG_MROUTE)
{
struct prefix_sg sg;
pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
sg.src = c_oil->oil.mfcc_origin;
sg.grp = c_oil->oil.mfcc_mcastgrp;
zlog_warn ("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s,%s): errno=%d: %s",
(unsigned long)SIOCGETSGCNT,
source_str,
group_str,
errno,
safe_strerror(errno));
zlog_warn ("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s): errno=%d: %s",
(unsigned long)SIOCGETSGCNT,
pim_str_sg_dump (&sg),
errno,
safe_strerror(errno));
}
return;
}

View File

@ -157,6 +157,10 @@ struct igmpmsg
#endif
#endif
#ifndef IGMPMSG_WRVIFWHOLE
#define IGMPMSG_WRVIFWHOLE 4 /* For PIM processing */
#endif
/*
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_del_vif(int vif_index);
int pim_mroute_add(struct channel_oil *c_oil);
int pim_mroute_del(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, const char *name);
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 "if.h"
#include "log.h"
#include "prefix.h"
#include "vty.h"
#include "plist.h"
#include "pimd.h"
#include "pim_vty.h"
#include "pim_pim.h"
#include "pim_msg.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,
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;
}
uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf,
int buf_size,
struct in_addr addr)
uint8_t *
pim_msg_addr_encode_ipv4_source(uint8_t *buf, int buf_size,
struct in_addr addr, uint8_t bits)
{
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[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 */
memcpy(buf+4, &addr, sizeof(struct in_addr));
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,
int buf_size,
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,
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 */

View File

@ -24,6 +24,8 @@
#include "prefix.h"
#include "memory.h"
#include "if.h"
#include "vty.h"
#include "plist.h"
#include "pimd.h"
#include "pim_neighbor.h"
@ -33,6 +35,8 @@
#include "pim_pim.h"
#include "pim_upstream.h"
#include "pim_ifchannel.h"
#include "pim_rp.h"
#include "pim_zebra.h"
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 (PIM_DEBUG_PIM_EVENTS) {
char dr_old_str[100];
char dr_new_str[100];
char dr_old_str[INET_ADDRSTRLEN];
char dr_new_str[INET_ADDRSTRLEN];
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));
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;
char msg[100];
zassert(t);
neigh = THREAD_ARG(t);
zassert(neigh);
ifp = neigh->interface;
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));
zlog_debug("Expired %d sec holdtime for neighbor %s on interface %s",
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);
pim_neighbor_delete(ifp, neigh, msg);
@ -237,26 +239,11 @@ static int on_neighbor_timer(struct thread *t)
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)
{
neigh->holdtime = holdtime;
neighbor_timer_off(neigh);
THREAD_OFF(neigh->t_expire_timer);
/*
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) {
char src_str[100];
char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
zlog_debug("%s: starting %u sec timer for neighbor %s on %s",
__PRETTY_FUNCTION__,
@ -290,15 +277,15 @@ static struct pim_neighbor *pim_neighbor_new(struct interface *ifp,
{
struct pim_interface *pim_ifp;
struct pim_neighbor *neigh;
char src_str[100];
char src_str[INET_ADDRSTRLEN];
zassert(ifp);
pim_ifp = ifp->info;
zassert(pim_ifp);
neigh = XMALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh));
neigh = XCALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh));
if (!neigh) {
zlog_err("%s: PIM XMALLOC(%zu) failure",
zlog_err("%s: PIM XCALLOC(%zu) failure",
__PRETTY_FUNCTION__, sizeof(*neigh));
return 0;
}
@ -311,10 +298,18 @@ static struct pim_neighbor *pim_neighbor_new(struct interface *ifp,
neigh->dr_priority = dr_priority;
neigh->generation_id = generation_id;
neigh->prefix_list = addr_list;
neigh->t_expire_timer = 0;
neigh->t_expire_timer = NULL;
neigh->interface = ifp;
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));
@ -391,7 +386,8 @@ struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
struct pim_neighbor *neigh;
pim_ifp = ifp->info;
zassert(pim_ifp);
if (!pim_ifp)
return NULL;
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
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,
@ -410,7 +434,8 @@ struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
uint16_t override_interval,
uint32_t dr_priority,
uint32_t generation_id,
struct list *addr_list)
struct list *addr_list,
int send_hello_now)
{
struct pim_interface *pim_ifp;
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
new Hello message should be sent on this interface after a
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;
}
@ -508,7 +546,7 @@ void pim_neighbor_delete(struct interface *ifp,
const char *delete_message)
{
struct pim_interface *pim_ifp;
char src_str[100];
char src_str[INET_ADDRSTRLEN];
pim_ifp = ifp->info;
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",
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);
@ -564,6 +602,8 @@ void pim_neighbor_delete(struct interface *ifp,
listnode_delete(pim_ifp->pim_neighbor_list, neigh);
pim_neighbor_free(neigh);
pim_neighbor_rpf_update();
}
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);
if (p) {
char addr_str[100];
char this_neigh_str[100];
char other_neigh_str[100];
char addr_str[INET_ADDRSTRLEN];
char this_neigh_str[INET_ADDRSTRLEN];
char other_neigh_str[INET_ADDRSTRLEN];
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));

View File

@ -25,6 +25,7 @@
#include "if.h"
#include "linklist.h"
#include "prefix.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);
struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
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 in_addr source_addr,
pim_hello_options hello_options,
@ -54,7 +61,8 @@ struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
uint16_t override_interval,
uint32_t dr_priority,
uint32_t generation_id,
struct list *addr_list);
struct list *addr_list,
int send_hello_now);
void pim_neighbor_delete(struct interface *ifp,
struct pim_neighbor *neigh,
const char *delete_message);

View File

@ -24,6 +24,8 @@
#include "memory.h"
#include "linklist.h"
#include "if.h"
#include "hash.h"
#include "jhash.h"
#include "pimd.h"
#include "pim_oil.h"
@ -31,104 +33,162 @@
#include "pim_iface.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)
{
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
into pim_channel_oil_free() because the later is
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);
}
static struct channel_oil *channel_oil_new(struct in_addr group_addr,
struct in_addr source_addr,
int input_vif_index)
static struct channel_oil *
pim_add_channel_oil (struct prefix_sg *sg,
int input_vif_index)
{
struct channel_oil *c_oil;
struct interface *ifp_in;
struct interface *ifp;
ifp_in = pim_if_find_by_vif_index(input_vif_index);
if (!ifp_in) {
ifp = pim_if_find_by_vif_index(input_vif_index);
if (!ifp) {
/* warning only */
char group_str[100];
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",
zlog_warn("%s: (S,G)=%s could not find input interface for input_vif_index=%d",
__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));
if (!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_origin = source_addr;
c_oil->oil.mfcc_mcastgrp = sg->grp;
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_ref_count = 1;
c_oil->installed = 0;
zassert(c_oil->oil_size == 0);
listnode_add_sort(pim_channel_oil_list, c_oil);
return c_oil;
}
static struct channel_oil *pim_add_channel_oil(struct in_addr group_addr,
struct in_addr source_addr,
int input_vif_index)
static struct channel_oil *pim_find_channel_oil(struct prefix_sg *sg)
{
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);
if (!c_oil) {
zlog_warn("PIM XCALLOC(%zu) failure", sizeof(*c_oil));
return 0;
}
lookup.oil.mfcc_mcastgrp = sg->grp;
lookup.oil.mfcc_origin = sg->src;
listnode_add(qpim_channel_oil_list, c_oil);
c_oil = hash_lookup (pim_channel_oil_hash, &lookup);
return c_oil;
}
static struct channel_oil *pim_find_channel_oil(struct in_addr group_addr,
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,
struct channel_oil *pim_channel_oil_add(struct prefix_sg *sg,
int input_vif_index)
{
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->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;
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)
@ -136,10 +196,96 @@ void pim_channel_oil_del(struct channel_oil *c_oil)
--c_oil->oil_ref_count;
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,
struct interface *oif,
uint32_t proto_mask)
@ -147,21 +293,18 @@ int pim_channel_add_oif(struct channel_oil *channel_oil,
struct pim_interface *pim_ifp;
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;
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
/*
Prevent creating MFC entry with OIF=IIF.
@ -175,10 +318,11 @@ int pim_channel_add_oif(struct channel_oil *channel_oil,
TODO T22.
*/
if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
channel_oil->oil_inherited_rescan = 1;
if (PIM_DEBUG_MROUTE)
{
char group_str[100];
char source_str[100];
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: 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 (PIM_DEBUG_MROUTE)
{
char group_str[100];
char source_str[100];
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: 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 (PIM_DEBUG_MROUTE)
{
char group_str[100];
char source_str[100];
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: 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 (PIM_DEBUG_MROUTE)
{
char group_str[100];
char source_str[100];
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: 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;
if (pim_mroute_add(channel_oil)) {
if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) {
if (PIM_DEBUG_MROUTE)
{
char group_str[100];
char source_str[100];
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 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;
if (PIM_DEBUG_MROUTE) {
char group_str[100];
char source_str[100];
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: DONE",
@ -286,3 +430,24 @@ int pim_channel_add_oif(struct channel_oil *channel_oil,
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
{
unsigned long long lastused;
unsigned long pktcnt;
unsigned long oldpktcnt;
unsigned long bytecnt;
@ -69,6 +70,7 @@ struct channel_counts
struct channel_oil {
struct mfcctl oil;
int installed;
int oil_inherited_rescan;
int oil_size;
int oil_ref_count;
time_t oif_creation[MAXVIFS];
@ -76,14 +78,22 @@ struct channel_oil {
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);
struct channel_oil *pim_channel_oil_add(struct in_addr group_addr,
struct in_addr source_addr,
struct channel_oil *pim_channel_oil_add(struct prefix_sg *sg,
int input_vif_index);
void pim_channel_oil_del(struct channel_oil *c_oil);
int pim_channel_add_oif(struct channel_oil *c_oil,
struct interface *oif,
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 */

View File

@ -44,6 +44,25 @@ static int on_pim_hello_send(struct thread *t);
static int pim_hello_send(struct interface *ifp,
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)
{
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);
}
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",
pim_ifp->pim_sock_fd, ifp->name,
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_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)
@ -114,67 +131,53 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
{
struct ip *ip_hdr;
size_t ip_hlen; /* ip header length in bytes */
char src_str[100];
char dst_str[100];
char src_str[INET_ADDRSTRLEN];
char dst_str[INET_ADDRSTRLEN];
uint8_t *pim_msg;
int pim_msg_len;
uint8_t pim_version;
uint8_t pim_type;
enum pim_msg_type pim_type;
uint16_t pim_checksum; /* received checksum */
uint16_t checksum; /* computed checksum */
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)) {
zlog_warn("PIM packet size=%zu shorter than minimum=%zu",
len, sizeof(*ip_hdr));
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("PIM packet size=%zu shorter than minimum=%zu",
len, sizeof(*ip_hdr));
return -1;
}
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 */
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) {
zlog_warn("IP packet protocol=%d is not PIM=%d",
ip_hdr->ip_p, PIM_IP_PROTO_PIM);
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("IP packet protocol=%d is not PIM=%d",
ip_hdr->ip_p, PIM_IP_PROTO_PIM);
return -1;
}
if (ip_hlen < PIM_IP_HEADER_MIN_LEN) {
zlog_warn("IP packet header size=%zu shorter than minimum=%d",
ip_hlen, PIM_IP_HEADER_MIN_LEN);
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("IP packet header size=%zu shorter than minimum=%d",
ip_hlen, PIM_IP_HEADER_MIN_LEN);
return -1;
}
if (ip_hlen > PIM_IP_HEADER_MAX_LEN) {
zlog_warn("IP packet header size=%zu greater than maximum=%d",
ip_hlen, PIM_IP_HEADER_MAX_LEN);
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("IP packet header size=%zu greater than maximum=%d",
ip_hlen, PIM_IP_HEADER_MAX_LEN);
return -1;
}
pim_msg = buf + 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) {
zlog_warn("PIM message size=%d shorter than minimum=%d",
pim_msg_len, PIM_PIM_MIN_LEN);
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("PIM message size=%d shorter than minimum=%d",
pim_msg_len, PIM_PIM_MIN_LEN);
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);
if (pim_version != PIM_PROTO_VERSION) {
zlog_warn("Ignoring PIM pkt from %s with unsupported version: %d",
ifp->name, pim_version);
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("Ignoring PIM pkt from %s with unsupported version: %d",
ifp->name, pim_version);
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);
if (checksum != pim_checksum) {
zlog_warn("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
ifp->name, pim_checksum, checksum);
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
ifp->name, pim_checksum, checksum);
return -1;
}
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",
src_str, dst_str, ifp->name, ip_hdr->ip_ttl,
pim_version, pim_type, pim_msg_len, checksum);
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));
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 ||
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)
switch (pim_type)
{
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) {
zlog_debug("Recv PIM packet type %d which is not currently understood",
pim_type);
}
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;
}
@ -278,80 +290,73 @@ static int pim_sock_read(struct thread *t)
int len;
ifindex_t ifindex = -1;
int result = -1; /* defaults to bad */
zassert(t);
static long long count = 0;
int cont = 1;
ifp = THREAD_ARG(t);
zassert(ifp);
fd = THREAD_FD(t);
pim_ifp = ifp->info;
zassert(pim_ifp);
zassert(fd == pim_ifp->pim_sock_fd);
len = pim_socket_recvfromto(fd, buf, sizeof(buf),
&from, &fromlen,
&to, &tolen,
&ifindex);
if (len < 0) {
zlog_warn("Failure receiving IP PIM packet on fd=%d: errno=%d: %s",
fd, errno, safe_strerror(errno));
goto done;
}
if (PIM_DEBUG_PIM_PACKETS) {
char from_str[100];
char to_str[100];
if (!inet_ntop(AF_INET, &from.sin_addr, from_str, sizeof(from_str)))
sprintf(from_str, "<from?>");
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);
}
while (cont)
{
len = pim_socket_recvfromto(fd, buf, sizeof(buf),
&from, &fromlen,
&to, &tolen,
&ifindex);
if (len < 0)
{
if (errno == EINTR)
continue;
if (errno == EWOULDBLOCK || errno == EAGAIN)
{
cont = 0;
break;
}
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug ("Received errno: %d %s", errno, safe_strerror (errno));
goto done;
}
#ifdef PIM_CHECK_RECV_IFINDEX_SANITY
/* ifindex sanity check */
if (ifindex != (int) ifp->ifindex) {
char from_str[100];
char to_str[100];
struct interface *recv_ifp;
/* ifindex sanity check */
if (ifindex != (int) ifp->ifindex) {
char from_str[INET_ADDRSTRLEN];
char to_str[INET_ADDRSTRLEN];
struct interface *recv_ifp;
if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str)))
sprintf(from_str, "<from?>");
if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str)))
sprintf(to_str, "<to?>");
if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str)))
sprintf(from_str, "<from?>");
if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str)))
sprintf(to_str, "<to?>");
recv_ifp = if_lookup_by_index(ifindex);
if (recv_ifp) {
zassert(ifindex == (int) recv_ifp->ifindex);
}
recv_ifp = if_lookup_by_index(ifindex);
if (recv_ifp) {
zassert(ifindex == (int) recv_ifp->ifindex);
}
#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)",
from_str, to_str, fd,
ifindex, recv_ifp ? recv_ifp->name : "<if-notfound>",
ifp->ifindex, ifp->name);
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,
ifindex, recv_ifp ? recv_ifp->name : "<if-notfound>",
ifp->ifindex, ifp->name);
#endif
goto done;
}
goto done;
}
#endif
int fail = pim_pim_packet(ifp, buf, len);
if (fail) {
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("%s: pim_pim_packet() return=%d",
__PRETTY_FUNCTION__, fail);
goto done;
}
int fail = pim_pim_packet(ifp, buf, len);
if (fail) {
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("%s: pim_pim_packet() return=%d",
__PRETTY_FUNCTION__, fail);
goto done;
}
count++;
if (count % qpim_packet_process == 0)
cont = 0;
}
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",
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);
THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp,
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_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_default_holdtime = -1; /* unset: means 3.5 * pim_hello_period */
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);
}
int pim_msg_send(int fd,
struct in_addr dst,
uint8_t *pim_msg,
int pim_msg_size,
const char *ifname)
static uint16_t ip_id = 0;
static int
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;
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) {
char dst_str[100];
char dst_str[INET_ADDRSTRLEN];
pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
__PRETTY_FUNCTION__,
@ -490,27 +568,8 @@ int pim_msg_send(int fd,
pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
}
sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT,
(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;
}
pim_msg_send_frame (fd, (char *)buffer, sendlen,
(struct sockaddr *)&to, tolen);
return 0;
}
@ -525,7 +584,7 @@ static int hello_send(struct interface *ifp,
pim_ifp = ifp->info;
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));
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__,
@ -560,6 +619,7 @@ static int hello_send(struct interface *ifp,
PIM_MSG_TYPE_HELLO);
if (pim_msg_send(pim_ifp->pim_sock_fd,
pim_ifp->primary_address,
qpim_all_pim_routers_addr,
pim_msg,
pim_msg_size,
@ -627,16 +687,14 @@ static int on_pim_hello_send(struct thread *t)
struct pim_interface *pim_ifp;
struct interface *ifp;
zassert(t);
ifp = THREAD_ARG(t);
zassert(ifp);
pim_ifp = ifp->info;
/*
* Schedule next hello
*/
pim_ifp->t_pim_hello_timer = 0;
pim_ifp->t_pim_hello_timer = NULL;
hello_resched(ifp);
/*
@ -692,7 +750,20 @@ void pim_hello_restart_triggered(struct interface *ifp)
pim_ifp = ifp->info;
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) {
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);
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) {
zlog_debug("Scheduling %d msec triggered hello on interface %s",
@ -729,8 +800,9 @@ int pim_sock_add(struct interface *ifp)
zassert(pim_ifp);
if (pim_ifp->pim_sock_fd >= 0) {
zlog_warn("Can't recreate existing PIM socket fd=%d for interface %s",
pim_ifp->pim_sock_fd, ifp->name);
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("Can't recreate existing PIM socket fd=%d for interface %s",
pim_ifp->pim_sock_fd, ifp->name);
return -1;
}
@ -738,12 +810,15 @@ int pim_sock_add(struct interface *ifp)
pim_ifp->pim_sock_fd = pim_sock_open(ifaddr, ifp->ifindex);
if (pim_ifp->pim_sock_fd < 0) {
zlog_warn("Could not open PIM socket on interface %s",
ifp->name);
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("Could not open PIM socket on interface %s",
ifp->name);
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();
/*

View File

@ -28,8 +28,6 @@
#define PIM_PIM_BUFSIZE_READ (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_TRIGGERED_HELLO_DELAY (5) /* seconds, RFC 4601: 4.11 */
#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_T_PERIODIC (60) /* RFC 4601: 4.11. Timer Values */
#define PIM_MSG_TYPE_HELLO (0)
#define PIM_MSG_TYPE_REGISTER (1)
#define PIM_MSG_TYPE_REG_STOP (2)
#define PIM_MSG_TYPE_JOIN_PRUNE (3)
#define PIM_MSG_TYPE_BOOTSTRAP (4)
#define PIM_MSG_TYPE_ASSERT (5)
#define PIM_MSG_TYPE_GRAFT (6)
#define PIM_MSG_TYPE_GRAFT_ACK (7)
#define PIM_MSG_TYPE_CANDIDATE (8)
enum pim_msg_type {
PIM_MSG_TYPE_HELLO = 0,
PIM_MSG_TYPE_REGISTER,
PIM_MSG_TYPE_REG_STOP,
PIM_MSG_TYPE_JOIN_PRUNE,
PIM_MSG_TYPE_BOOTSTRAP,
PIM_MSG_TYPE_ASSERT,
PIM_MSG_TYPE_GRAFT,
PIM_MSG_TYPE_GRAFT_ACK,
PIM_MSG_TYPE_CANDIDATE
};
#define PIM_MSG_HDR_OFFSET_VERSION(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_msg_send(int fd,
struct in_addr src,
struct in_addr dst,
uint8_t *pim_msg,
int pim_msg_size,

View File

@ -24,6 +24,9 @@
#include "log.h"
#include "if.h"
#include "thread.h"
#include "prefix.h"
#include "vty.h"
#include "plist.h"
#include "pimd.h"
#include "pim_mroute.h"
@ -39,65 +42,150 @@
#include "pim_oil.h"
#include "pim_zebra.h"
#include "pim_join.h"
#include "pim_util.h"
struct thread *send_test_packet_timer = NULL;
/*
* This seems stupidly expensive. A list lookup. Why is this
* not a hash?
*/
static int
pim_check_is_my_ip_address (struct in_addr dest_addr)
void
pim_register_stop_send (struct interface *ifp, struct prefix_sg *sg,
struct in_addr src, struct in_addr originator)
{
/*
* 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(dest_addr) && (dest_addr.s_addr == qpim_rp.rpf_addr.s_addr))
return 1;
struct pim_interface *pinfo;
unsigned char buffer[10000];
unsigned int b1length = 0;
unsigned int length;
uint8_t *b1;
struct prefix p;
if (if_lookup_exact_address (&dest_addr, AF_INET))
return 1;
if (PIM_DEBUG_PIM_REG)
{
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;
}
static void
pim_register_stop_send (struct in_addr src)
{
return;
}
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;
struct pim_interface *pinfo;
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;
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;
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;
}
memset(buffer, 0, 3000);
memset(buffer, 0, 10000);
b1 = buffer + PIM_MSG_HEADER_LEN;
*b1 |= null_register << 6;
b1 = buffer + PIM_MSG_REGISTER_LEN;
plen = ntohs(ip_hdr->ip_len);
memcpy(b1, (const unsigned char *)ip_hdr, plen);
memcpy(b1, (const unsigned char *)buf, buf_size);
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,
rpg->rpf_addr,
src,
rpg->rpf_addr.u.prefix4,
buffer,
plen + PIM_MSG_REGISTER_LEN,
buf_size + PIM_MSG_REGISTER_LEN,
ifp->name)) {
if (PIM_DEBUG_PIM_TRACE) {
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;
struct ip *ip_hdr;
//size_t hlen;
struct in_addr group = { .s_addr = 0 };
struct in_addr source = { .s_addr = 0 };
//uint8_t *msg;
struct prefix_sg sg;
uint32_t *bits;
int i_am_rp = 0;
if (!pim_check_is_my_ip_address (dest_addr)) {
if (PIM_DEBUG_PIM_PACKETS) {
char dest[100];
#define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4
ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN);
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));
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;
}
#define inherited_olist(S,G) NULL
/*
* 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
* start of the actual Encapsulated data.
*/
#define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4
ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN);
//hlen = (ip_hdr->ip_hl << 2) | PIM_MSG_REGISTER_LEN;
//msg = (uint8_t *)tlv_buf + hlen;
source = ip_hdr->ip_src;
group = ip_hdr->ip_dst;
memset (&sg, 0, sizeof (struct prefix_sg));
sg.src = ip_hdr->ip_src;
sg.grp = 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;
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)
zlog_debug("%s: Received Register message with Border bit set", __func__);
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) {
pim_register_stop_send(src_addr);
pim_register_stop_send (ifp, &sg, dest_addr, src_addr);
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("%s: Sending register-Stop to %s and dropping mr. packet",
__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 (!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) ||
((SwitchToSptDesired(source, group)) &&
(inherited_olist(source, group) == NULL))) {
pim_register_stop_send(src_addr);
((SwitchToSptDesired(&sg)) &&
pim_upstream_inherited_olist (upstream) == 0)) {
//pim_scan_individual_oil (upstream->channel_oil);
pim_register_stop_send (ifp, &sg, dest_addr, src_addr);
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) ||
(SwitchToSptDesired(source, group))) {
(SwitchToSptDesired(&sg))) {
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 {
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) &&
!(*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
//inherited_olist(S,G,rpt)
// This is taken care of by the kernel for us
}
pim_upstream_msdp_reg_timer_start(upstream);
} 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;
}
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_STOP_LEN (4)
void pim_register_send_test_packet_start (struct in_addr source,
struct in_addr group,
uint32_t pps);
int pim_register_stop_recv (uint8_t *buf, int buf_size);
int pim_register_recv (struct interface *ifp,
struct in_addr dest_addr,
struct in_addr src_addr,
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

View File

@ -20,48 +20,597 @@
*/
#include <zebra.h>
#include "lib/json.h"
#include "log.h"
#include "network.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 "pim_vty.h"
#include "pim_str.h"
#include "pim_iface.h"
#include "pim_rp.h"
#include "pim_str.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;
/*
* Checks to see if we should elect ourself the actual RP
*/
void
pim_rp_check_rp (struct in_addr old, struct in_addr new)
struct rp_info
{
if (PIM_DEBUG_ZEBRA) {
char sold[100];
char snew[100];
char rp[100];
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 );
}
struct prefix group;
struct pim_rpf rp;
int i_am_rp;
char *plist;
};
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;
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;
return;
if (rp.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr &&
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;
return;
if (rp_info->plist && strcmp(rp_info->plist, plist) == 0)
{
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
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 *
pim_rp_g (struct in_addr group)
{
/*
* For staticly configured RP, it is always the qpim_rp
*/
pim_nexthop_lookup(&qpim_rp.source_nexthop, qpim_rp.rpf_addr, NULL);
return(&qpim_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)
{
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
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)
zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__);
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;
}
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
#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_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);
#define I_am_RP(G) pim_rp_i_am_rp ((G))
#define RP(G) pim_rp_g ((G))
void pim_rp_show_information (struct vty *vty, u_char uj);
#endif

View File

@ -33,108 +33,160 @@
#include "pim_iface.h"
#include "pim_zlookup.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);
int pim_nexthop_lookup(struct pim_nexthop *nexthop,
struct in_addr addr, struct interface *incoming)
void
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;
struct interface *ifp;
int first_ifindex;
struct interface *ifp = NULL;
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 (!incoming)
if ((nexthop->last_lookup.s_addr == addr.s_addr) &&
(nexthop->last_lookup_time > last_route_change_time))
{
num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
PIM_NEXTHOP_IFINDEX_TAB_SIZE,
addr, PIM_NEXTHOP_LOOKUP_MAX);
if (num_ifindex < 1) {
char addr_str[100];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_warn("%s %s: could not find nexthop ifindex for address %s",
__FILE__, __PRETTY_FUNCTION__,
addr_str);
return -1;
}
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;
}
if (PIM_DEBUG_TRACE)
{
char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug ("%s: Using last lookup for %s at %lld, %lld",
__PRETTY_FUNCTION__,
addr_str,
nexthop->last_lookup_time,
last_route_change_time);
}
nexthop_lookups_avoided++;
return 0;
}
else
{
ifp = incoming;
first_ifindex = ifp->ifindex;
if (PIM_DEBUG_TRACE)
{
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) {
char addr_str[100];
memset (nexthop_tab, 0, sizeof (struct pim_zlookup_nexthop) * MULTIPATH_NUM);
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));
zlog_warn("%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)",
__PRETTY_FUNCTION__,
ifp->name, first_ifindex, addr_str);
/* debug warning only, do not return */
zlog_warn("%s %s: could not find nexthop ifindex for address %s",
__FILE__, __PRETTY_FUNCTION__,
addr_str);
return -1;
}
if (PIM_DEBUG_PIM_TRACE) {
char nexthop_str[100];
char addr_str[100];
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);
}
while (!found && (i < num_ifindex))
{
first_ifindex = nexthop_tab[i].ifindex;
/* update nextop data */
nexthop->interface = ifp;
nexthop->mrib_nexthop_addr = nexthop_tab[0].nexthop_addr;
nexthop->mrib_metric_preference = nexthop_tab[0].protocol_distance;
nexthop->mrib_route_metric = nexthop_tab[0].route_metric;
ifp = if_lookup_by_index(first_ifindex);
if (!ifp)
{
if (PIM_DEBUG_ZEBRA)
{
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,
const struct pim_nexthop *nh2)
{
return (nh1->interface != nh2->interface)
||
(nh1->mrib_nexthop_addr.s_addr != nh2->mrib_nexthop_addr.s_addr)
||
(nh1->mrib_metric_preference != nh2->mrib_metric_preference)
||
return (nh1->interface != nh2->interface) ||
(nh1->mrib_nexthop_addr.u.prefix4.s_addr != nh2->mrib_nexthop_addr.u.prefix4.s_addr) ||
(nh1->mrib_metric_preference != nh2->mrib_metric_preference) ||
(nh1->mrib_route_metric != nh2->mrib_route_metric);
}
enum pim_rpf_result pim_rpf_update(struct pim_upstream *up,
struct in_addr *old_rpf_addr,
struct interface *incoming)
enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct in_addr *old_rpf_addr)
{
struct in_addr save_rpf_addr;
struct prefix save_rpf_addr;
struct pim_nexthop save_nexthop;
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) */
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;
}
rpf->rpf_addr = pim_rpf_find_rpf_addr(up);
if (PIM_INADDR_IS_ANY(rpf->rpf_addr) && PIM_DEBUG_PIM_EVENTS) {
rpf->rpf_addr.family = AF_INET;
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 */
char src_str[100];
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",
zlog_debug("%s %s: RPF'%s not found: won't send join upstream",
__FILE__, __PRETTY_FUNCTION__,
src_str, grp_str);
up->sg_str);
/* warning only */
}
/* detect change in pim_nexthop */
if (nexthop_mismatch(&rpf->source_nexthop, &save_nexthop)) {
if (PIM_DEBUG_PIM_EVENTS) {
char src_str[100];
char grp_str[100];
char nhaddr_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));
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",
if (PIM_DEBUG_ZEBRA) {
char nhaddr_str[PREFIX_STRLEN];
pim_addr_dump("<addr?>", &rpf->source_nexthop.mrib_nexthop_addr, nhaddr_str, sizeof(nhaddr_str));
zlog_debug("%s %s: (S,G)=%s source nexthop now is: interface=%s address=%s pref=%d metric=%d",
__FILE__, __PRETTY_FUNCTION__,
src_str, grp_str,
up->sg_str,
rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "<ifname?>",
nhaddr_str,
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) */
if (save_nexthop.interface != rpf->source_nexthop.interface) {
if (PIM_DEBUG_PIM_EVENTS) {
char src_str[100];
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",
if (PIM_DEBUG_ZEBRA) {
zlog_debug("%s %s: (S,G)=%s RPF_interface(S) changed from %s to %s",
__FILE__, __PRETTY_FUNCTION__,
src_str, grp_str,
up->sg_str,
save_nexthop.interface ? save_nexthop.interface->name : "<oldif?>",
rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "<newif?>");
/* warning only */
@ -203,11 +246,11 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up,
}
/* 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 ? */
if (old_rpf_addr)
*old_rpf_addr = save_rpf_addr;
*old_rpf_addr = save_rpf_addr.u.prefix4;
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;
if (!up->rpf.source_nexthop.interface) {
char src_str[100];
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)",
zlog_warn("%s: missing RPF interface for upstream (S,G)=%s",
__PRETTY_FUNCTION__,
src_str, grp_str);
up->sg_str);
rpf_addr.s_addr = PIM_NET_INADDR_ANY;
return rpf_addr;
}
rpf_ch = pim_ifchannel_find(up->rpf.source_nexthop.interface,
up->source_addr, up->group_addr);
&up->sg);
if (rpf_ch) {
if (rpf_ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
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 ) ) */
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)
rpf_addr = neigh->source_addr;
else
@ -268,3 +307,52 @@ static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up)
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_neighbor.h"
int pim_nexthop_lookup(struct pim_nexthop *nexthop,
struct in_addr addr, struct interface *incoming);
enum pim_rpf_result pim_rpf_update(struct pim_upstream *up,
struct in_addr *old_rpf_addr,
struct interface *incoming);
/*
RFC 4601:
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 */

View File

@ -44,7 +44,8 @@
/* GLOBAL VARS */
extern struct zebra_privs_t pimd_privs;
int pim_socket_raw(int protocol)
int
pim_socket_raw (int protocol)
{
int fd;
@ -67,8 +68,58 @@ int pim_socket_raw(int protocol)
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 rcvbuf = 1024 * 1024 * 8;
#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
struct ip_mreqn mreq;
#else
struct ip_mreq mreq;
#endif
int fd;
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);
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));
ret = pim_socket_bind (fd, ifp);
if (ret)
{
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;
}
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,
(void *) &ifaddr, sizeof(ifaddr))) {
(void *) &mreq, sizeof(mreq))) {
zlog_warn("Could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s",
fd, errno, safe_strerror(errno));
close(fd);
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;
@ -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));
if (ret) {
char group_str[100];
char ifaddr_str[100];
char group_str[INET_ADDRSTRLEN];
char ifaddr_str[INET_ADDRSTRLEN];
if (!inet_ntop(AF_INET, &group, group_str , sizeof(group_str)))
sprintf(group_str, "<group?>");
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) {
char group_str[100];
char ifaddr_str[100];
char group_str[INET_ADDRSTRLEN];
char ifaddr_str[INET_ADDRSTRLEN];
if (!inet_ntop(AF_INET, &group, group_str , sizeof(group_str)))
sprintf(group_str, "<group?>");
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)
{
if (pim_igmp_join_source(fd, ifindex, group_addr, source_addr)) {
int e = errno;
char group_str[100];
char source_str[100];
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_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",
__PRETTY_FUNCTION__,
fd, group_str, source_str, ifindex, ifname,
e, safe_strerror(e));
errno, safe_strerror(errno));
return -1;
}
@ -298,17 +352,14 @@ int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
if (to) {
struct sockaddr_in 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)) {
((struct sockaddr_in *) to)->sin_port = ntohs(0);
((struct sockaddr_in *) to)->sin_addr.s_addr = ntohl(0);
}
else {
((struct sockaddr_in *) to)->sin_port = si.sin_port;
((struct sockaddr_in *) to)->sin_addr = si.sin_addr;
}
memset (&si, 0, sizeof (si));
to->sin_family = AF_INET;
pim_socket_getsockname(fd, (struct sockaddr *) &si, &si_len);
to->sin_port = si.sin_port;
to->sin_addr = si.sin_addr;
if (tolen)
*tolen = sizeof(si);
@ -346,14 +397,6 @@ int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
if (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;
}
#endif
@ -366,14 +409,6 @@ int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
if (tolen)
*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;
}
#endif

View File

@ -36,6 +36,8 @@
#define PIM_SOCK_ERR_NAME (-10) /* Socket name (getsockname) */
#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_mcast(int protocol, struct in_addr ifaddr, int ifindex, u_char loop);
int pim_socket_join(int fd, struct in_addr group,

View File

@ -25,11 +25,10 @@
#include "memory.h"
#include "sockopt.h"
#include "pimd.h"
#include "pim_ssmpingd.h"
#include "pim_time.h"
#include "pim_sock.h"
#include "pim_str.h"
#include "pimd.h"
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);
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));
zlog_warn("%s: bind(fd=%d,addr=%s,port=%d,len=%zu) failure: errno=%d: %s",
__PRETTY_FUNCTION__,
@ -195,12 +194,11 @@ static void ssmpingd_delete(struct ssmpingd_sock *ss)
THREAD_OFF(ss->t_sock_read);
if (close(ss->sock_fd)) {
int e = errno;
char source_str[100];
char source_str[INET_ADDRSTRLEN];
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",
__PRETTY_FUNCTION__,
ss->sock_fd, source_str, e, safe_strerror(e));
ss->sock_fd, source_str, errno, safe_strerror(errno));
/* warning only */
}
@ -219,14 +217,13 @@ static void ssmpingd_sendto(struct ssmpingd_sock *ss,
sent = sendto(ss->sock_fd, buf, len, MSG_DONTWAIT,
(struct sockaddr *)&to, tolen);
if (sent != len) {
int e = errno;
char to_str[100];
char to_str[INET_ADDRSTRLEN];
pim_inet4_dump("<to?>", to.sin_addr, to_str, sizeof(to_str));
if (sent < 0) {
zlog_warn("%s: sendto() failure to %s,%d: fd=%d len=%d: errno=%d: %s",
__PRETTY_FUNCTION__,
to_str, ntohs(to.sin_port), ss->sock_fd, len,
e, safe_strerror(e));
errno, safe_strerror(errno));
}
else {
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,
&ifindex);
if (len < 0) {
char source_str[100];
char source_str[INET_ADDRSTRLEN];
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",
__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);
if (buf[0] != PIM_SSMPINGD_REQUEST) {
char source_str[100];
char from_str[100];
char to_str[100];
char source_str[INET_ADDRSTRLEN];
char from_str[INET_ADDRSTRLEN];
char to_str[INET_ADDRSTRLEN];
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("<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) {
char source_str[100];
char from_str[100];
char to_str[100];
char source_str[INET_ADDRSTRLEN];
char from_str[INET_ADDRSTRLEN];
char to_str[INET_ADDRSTRLEN];
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("<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 result;
zassert(t);
ss = THREAD_ARG(t);
zassert(ss);
sock_fd = THREAD_FD(t);
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);
if (sock_fd < 0) {
char source_str[100];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: ssmpingd_socket() failure for source %s",
__PRETTY_FUNCTION__, source_str);
return 0;
}
ss = XMALLOC(MTYPE_PIM_SSMPINGD, sizeof(*ss));
ss = XCALLOC(MTYPE_PIM_SSMPINGD, sizeof(*ss));
if (!ss) {
char source_str[100];
char source_str[INET_ADDRSTRLEN];
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__,
sizeof(*ss), source_str);
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));
zlog_info("%s: starting ssmpingd for source %s",
__PRETTY_FUNCTION__, source_str);
@ -407,7 +401,7 @@ int pim_ssmpingd_start(struct in_addr source_addr)
ss = ssmpingd_new(source_addr);
if (!ss) {
char source_str[100];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: ssmpingd_new() failure for source %s",
__PRETTY_FUNCTION__, source_str);
@ -423,7 +417,7 @@ int pim_ssmpingd_stop(struct in_addr source_addr)
ss = ssmpingd_find(source_addr);
if (!ss) {
char source_str[100];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: could not find ssmpingd for source %s",
__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));
zlog_info("%s: stopping ssmpingd for source %s",
__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)
{
struct listnode *node = 0;
struct static_route *s_route = 0;
struct static_route *original_s_route = 0;
struct pim_interface *pim_iif = iif ? iif->info : 0;
struct pim_interface *pim_oif = oif ? oif->info : 0;
struct listnode *node = NULL;
struct static_route *s_route = NULL;
struct static_route *original_s_route = NULL;
struct pim_interface *pim_iif = iif ? iif->info : NULL;
struct pim_interface *pim_oif = oif ? oif->info : NULL;
ifindex_t iif_index = pim_iif ? pim_iif->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) {
if (s_route->iif == iif_index &&
s_route->oif_ttls[oif_index]) {
char gifaddr_str[100];
char sifaddr_str[100];
char gifaddr_str[INET_ADDRSTRLEN];
char sifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_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)",
@ -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);
}
if (pim_mroute_add(&s_route->c_oil))
if (pim_mroute_add(&s_route->c_oil, __PRETTY_FUNCTION__))
{
char gifaddr_str[100];
char sifaddr_str[100];
char gifaddr_str[INET_ADDRSTRLEN];
char sifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_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)",
@ -209,8 +209,8 @@ int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr
}
if (PIM_DEBUG_STATIC) {
char gifaddr_str[100];
char sifaddr_str[100];
char gifaddr_str[INET_ADDRSTRLEN];
char sifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_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)",
@ -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)
{
struct listnode *node = 0;
struct listnode *nextnode = 0;
struct static_route *s_route = 0;
struct listnode *node = NULL;
struct listnode *nextnode = NULL;
struct static_route *s_route = NULL;
struct pim_interface *pim_iif = iif ? iif->info : 0;
struct pim_interface *pim_oif = oif ? oif->info : 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 (s_route->c_oil.oil_ref_count <= 0 ?
pim_mroute_del(&s_route->c_oil) : pim_mroute_add(&s_route->c_oil)) {
char gifaddr_str[100];
char sifaddr_str[100];
pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_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)",
pim_mroute_del(&s_route->c_oil, __PRETTY_FUNCTION__) : pim_mroute_add(&s_route->c_oil, __PRETTY_FUNCTION__)) {
char gifaddr_str[INET_ADDRSTRLEN];
char sifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_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)",
__FILE__, __PRETTY_FUNCTION__,
iif_index,
oif_index,
gifaddr_str,
sifaddr_str);
s_route->oif_ttls[oif_index] = 1;
s_route->c_oil.oil.mfcc_ttls[oif_index] = 1;
++s_route->c_oil.oil_ref_count;
s_route->oif_ttls[oif_index] = 1;
s_route->c_oil.oil.mfcc_ttls[oif_index] = 1;
++s_route->c_oil.oil_ref_count;
return -1;
return -1;
}
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) {
char gifaddr_str[100];
char sifaddr_str[100];
char gifaddr_str[INET_ADDRSTRLEN];
char sifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_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)",
@ -297,8 +297,8 @@ int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr
}
if (!node) {
char gifaddr_str[100];
char sifaddr_str[100];
char gifaddr_str[INET_ADDRSTRLEN];
char sifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_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)",
@ -319,8 +319,8 @@ pim_static_write_mroute (struct vty *vty, struct interface *ifp)
struct listnode *node;
struct static_route *sroute;
int count = 0;
char sbuf[100];
char gbuf[100];
char sbuf[INET_ADDRSTRLEN];
char gbuf[INET_ADDRSTRLEN];
for (ALL_LIST_ELEMENTS_RO (qpim_static_route_list, node, sroute))
{

View File

@ -28,17 +28,62 @@
#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;
if (!inet_ntop(AF_INET, &addr, buf, buf_size)) {
int e = errno;
zlog_warn("pim_inet4_dump: inet_ntop(AF_INET,buf_size=%d): errno=%d: %s",
buf_size, e, safe_strerror(e));
if (!inet_ntop(p->family, &p->u.prefix, buf, buf_size)) {
zlog_warn("pim_addr_dump: inet_ntop(buf_size=%d): errno=%d: %s",
buf_size, errno, safe_strerror(errno));
if (onfail)
snprintf(buf, buf_size, "%s", onfail);
}
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 <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);
char *pim_str_sg_dump (const struct prefix_sg *sg);
char *pim_str_sg_set (const struct prefix_sg *sg, char *sg_str);
#endif

View File

@ -82,6 +82,25 @@ int64_t pim_time_monotonic_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)
{
long mm;

View File

@ -28,6 +28,7 @@
int64_t pim_time_monotonic_sec(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);
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);

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))
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)
{
@ -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,
const uint8_t *buf_pastend,
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)
return 0;
l_encode = pim_encode_unicast_address (curr, p);
l_encode = pim_encode_addr_ucast (curr, p);
curr += 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)
{
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));
zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s",
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)
{
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));
zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
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)
{
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));
zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
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)
{
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));
zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s",
label, tlv_name,
@ -408,7 +508,7 @@ pim_parse_addr_ucast (struct prefix *p,
}
int
pim_parse_addr_group (struct prefix *p,
pim_parse_addr_group (struct prefix_sg *sg,
const uint8_t *buf,
int buf_size)
{
@ -450,17 +550,15 @@ pim_parse_addr_group (struct prefix *p,
return -3;
}
p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
p->prefixlen = mask_len;
memcpy(&sg->grp.s_addr, addr, sizeof(struct in_addr));
addr += sizeof(struct in_addr);
break;
default:
{
zlog_warn("%s: unknown group address encoding family=%d from",
__PRETTY_FUNCTION__, family);
zlog_warn("%s: unknown group address encoding family=%d mask_len=%d from",
__PRETTY_FUNCTION__, family, mask_len);
return -4;
}
}
@ -469,7 +567,7 @@ pim_parse_addr_group (struct prefix *p,
}
int
pim_parse_addr_source(struct prefix *p,
pim_parse_addr_source(struct prefix_sg *sg,
uint8_t *flags,
const uint8_t *buf,
int buf_size)
@ -513,9 +611,7 @@ pim_parse_addr_source(struct prefix *p,
return -3;
}
p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
p->prefixlen = mask_len;
memcpy(&sg->src, addr, sizeof(struct in_addr));
/*
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
received with any other mask length.
*/
if (p->prefixlen != 32) {
if (mask_len != 32) {
zlog_warn("%s: IPv4 bad source address mask: %d",
__PRETTY_FUNCTION__, p->prefixlen);
__PRETTY_FUNCTION__, mask_len);
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);
if (addr_offset < 1) {
char src_str[100];
char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
__PRETTY_FUNCTION__,
@ -599,8 +695,8 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
switch (tmp.family) {
case AF_INET:
{
char addr_str[100];
char src_str[100];
char addr_str[INET_ADDRSTRLEN];
char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", tmp.u.prefix4, addr_str, sizeof(addr_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",
@ -612,7 +708,7 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
break;
default:
{
char src_str[100];
char src_str[INET_ADDRSTRLEN];
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",
__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.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));
zlog_warn("%s: ignoring primary address in secondary list from %s on %s",
__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,
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,
const uint8_t *buf,
int buf_size);
int pim_parse_addr_group (struct prefix *p,
int pim_parse_addr_group (struct prefix_sg *sg,
const uint8_t *buf,
int buf_size);
int pim_parse_addr_source(struct prefix *p,
int pim_parse_addr_source(struct prefix_sg *sg,
uint8_t *flags,
const uint8_t *buf,
int buf_size);

File diff suppressed because it is too large Load Diff

View File

@ -22,52 +22,47 @@
#define PIM_UPSTREAM_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_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_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_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_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
/*
RFC 4601:
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 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
};
#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)
#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)
#define PIM_UPSTREAM_FLAG_UNSET_SRC_MSDP(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
enum pim_upstream_state {
PIM_UPSTREAM_NOTJOINED,
PIM_UPSTREAM_JOINED
PIM_UPSTREAM_JOINED,
PIM_UPSTREAM_JOIN_PENDING,
PIM_UPSTREAM_PRUNE,
};
enum pim_upstream_sptbit {
@ -83,11 +78,14 @@ enum pim_upstream_sptbit {
See RFC 4601: 4.5.7. Sending (S,G) Join/Prune Message
*/
struct pim_upstream {
struct pim_upstream *parent;
struct in_addr upstream_addr;/* Who we are talking to */
struct in_addr source_addr; /* (S,G) source key */
struct in_addr group_addr; /* (S,G) group key */
struct in_addr upstream_register; /*Who we received a register from*/
struct prefix_sg sg; /* (S,G) group key */
char sg_str[PIM_SG_LEN];
uint32_t flags;
struct channel_oil *channel_oil;
struct list *sources;
enum pim_upstream_state join_state;
enum pim_upstream_sptbit sptbit;
@ -98,6 +96,13 @@ struct pim_upstream {
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)
*/
@ -105,17 +110,23 @@ struct pim_upstream {
#define PIM_KEEPALIVE_PERIOD (210)
#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 */
};
struct list *pim_upstream_list;
struct hash *pim_upstream_hash;
void pim_upstream_free(struct pim_upstream *up);
void pim_upstream_delete(struct pim_upstream *up);
struct pim_upstream *pim_upstream_find(struct in_addr source_addr,
struct in_addr group_addr);
struct pim_upstream *pim_upstream_add(struct in_addr source_addr,
struct in_addr group_addr,
struct interface *ifp);
void pim_upstream_del(struct pim_upstream *up);
struct pim_upstream *pim_upstream_find (struct prefix_sg *sg);
struct pim_upstream *pim_upstream_add (struct prefix_sg *sg,
struct interface *ifp, int flags,
const char *name);
void pim_upstream_del(struct pim_upstream *up, const char *name);
int pim_upstream_evaluate_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);
int pim_upstream_switch_to_spt_desired (struct in_addr source, struct in_addr group);
#define SwitchToSptDesired(S,G) pim_upstream_switch_to_spt_desired ((S), (G))
int pim_upstream_switch_to_spt_desired (struct prefix_sg *sg);
#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 */

View File

@ -21,6 +21,7 @@
#include <zebra.h>
#include "log.h"
#include "prefix.h"
#include "pim_util.h"
@ -103,3 +104,43 @@ void pim_pkt_dump(const char *label, const uint8_t *buf, int size)
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);
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 */

View File

@ -22,7 +22,10 @@
#include "if.h"
#include "linklist.h"
#include "prefix.h"
#include "vty.h"
#include "vrf.h"
#include "plist.h"
#include "pimd.h"
#include "pim_vty.h"
@ -33,11 +36,26 @@
#include "pim_pim.h"
#include "pim_oil.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;
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) {
vty_out(vty, "debug igmp events%s", VTY_NEWLINE);
++writes;
@ -50,12 +68,21 @@ int pim_debug_config_write(struct vty *vty)
vty_out(vty, "debug igmp trace%s", VTY_NEWLINE);
++writes;
}
if (PIM_DEBUG_IGMP_TRACE_DETAIL) {
vty_out(vty, "debug igmp trace detail%s", VTY_NEWLINE);
++writes;
}
if (PIM_DEBUG_MROUTE) {
vty_out(vty, "debug mroute%s", VTY_NEWLINE);
++writes;
}
if (PIM_DEBUG_MROUTE_DETAIL) {
vty_out (vty, "debug mroute detail%s", VTY_NEWLINE);
++writes;
}
if (PIM_DEBUG_PIM_EVENTS) {
vty_out(vty, "debug pim events%s", VTY_NEWLINE);
++writes;
@ -72,10 +99,15 @@ int pim_debug_config_write(struct vty *vty)
vty_out(vty, "debug pim packet-dump receive%s", VTY_NEWLINE);
++writes;
}
if (PIM_DEBUG_PIM_TRACE) {
vty_out(vty, "debug pim trace%s", VTY_NEWLINE);
++writes;
}
if (PIM_DEBUG_PIM_TRACE_DETAIL) {
vty_out(vty, "debug pim trace detail%s", VTY_NEWLINE);
++writes;
}
if (PIM_DEBUG_ZEBRA) {
vty_out(vty, "debug pim zebra%s", VTY_NEWLINE);
@ -87,22 +119,66 @@ int pim_debug_config_write(struct vty *vty)
++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;
}
int pim_global_config_write(struct vty *vty)
{
int writes = 0;
char buffer[32];
writes += pim_msdp_config_write (vty);
if (PIM_MROUTE_IS_ENABLED) {
vty_out(vty, "ip multicast-routing%s", VTY_NEWLINE);
++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;
}
writes += pim_rp_config_write (vty);
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) {
struct listnode *node;
@ -110,7 +186,7 @@ int pim_global_config_write(struct vty *vty)
vty_out(vty, "!%s", VTY_NEWLINE);
++writes;
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));
vty_out(vty, "ip ssmpingd %s%s", source_str, VTY_NEWLINE);
++writes;
@ -159,12 +235,30 @@ int pim_interface_config_write(struct vty *vty)
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 (PIM_IF_TEST_IGMP(pim_ifp->options)) {
vty_out(vty, " ip igmp%s", VTY_NEWLINE);
++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 (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 (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,
VTY_NEWLINE);
++writes;
@ -188,10 +282,10 @@ int pim_interface_config_write(struct vty *vty)
struct listnode *node;
struct igmp_join *ij;
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_join_list, node, ij)) {
char group_str[100];
char source_str[100];
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
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",
group_str, source_str,
VTY_NEWLINE);

View File

@ -28,6 +28,8 @@
#include "zclient.h"
#include "stream.h"
#include "network.h"
#include "vty.h"
#include "plist.h"
#include "pimd.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)) {
pim_ifchannel_delete_all(ifp);
/*
pim_if_addr_del_all() suffices for shutting down IGMP,
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;
}
@ -220,7 +226,7 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
{
struct connected *c;
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
@ -234,10 +240,9 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
if (!c)
return 0;
pim_ifp = c->ifp->info;
p = c->address;
if (p->family != AF_INET)
return 0;
if (PIM_DEBUG_ZEBRA) {
char buf[BUFSIZ];
prefix2str(p, buf, BUFSIZ);
@ -251,7 +256,25 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
#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)) {
/* 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 */
char buf[BUFSIZ];
char old[100];
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__,
c->ifp->name, old, buf);
c->ifp->name, buf);
}
SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
}
}
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;
}
@ -285,7 +320,6 @@ static int pim_zebra_if_address_del(int command, struct zclient *client,
{
struct connected *c;
struct prefix *p;
struct in_addr new = { .s_addr = 0 };
/*
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
}
pim_rp_check_rp (p->u.prefix4, new);
pim_if_addr_del(c, 0);
pim_rp_setup();
pim_i_am_rp_re_evaluate();
return 0;
}
@ -328,18 +363,37 @@ static void scan_upstream_rpf_cache()
struct listnode *up_nextnode;
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 interface *old_interface;
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)
continue;
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 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
@ -356,17 +410,13 @@ static void scan_upstream_rpf_cache()
/* send Prune(S,G) to the old upstream neighbor */
pim_joinprune_send(up->rpf.source_nexthop.interface,
old_rpf_addr,
up->source_addr,
up->group_addr,
0 /* prune */);
pim_joinprune_send(old_interface, old_rpf_addr,
up, 0 /* prune */);
/* send Join(S,G) to the current upstream neighbor */
pim_joinprune_send(up->rpf.source_nexthop.interface,
up->rpf.rpf_addr,
up->source_addr,
up->group_addr,
up->rpf.rpf_addr.u.prefix4,
up,
1 /* join */);
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 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;
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)
{
char source_str[100];
char group_str[100];
char source_str[INET_ADDRSTRLEN];
char group_str[INET_ADDRSTRLEN];
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));
zlog_debug("%s %s: could not find input interface(%d) for (S,G)=(%s,%s)",
__FILE__, __PRETTY_FUNCTION__, c_oil->oil.mfcc_parent,
source_str, group_str);
}
pim_mroute_del (c_oil);
pim_mroute_del (c_oil, __PRETTY_FUNCTION__);
return;
}
if (input_iface_vif_index == c_oil->oil.mfcc_parent)
{
if (!c_oil->installed)
pim_mroute_add (c_oil, __PRETTY_FUNCTION__);
/* RPF unchanged */
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 *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
char source_str[100];
char group_str[100];
char source_str[INET_ADDRSTRLEN];
char group_str[INET_ADDRSTRLEN];
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));
zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
__FILE__, __PRETTY_FUNCTION__,
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);
old_iif->name, c_oil->oil.mfcc_parent,
new_iif->name, input_iface_vif_index);
}
/* 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);
if (PIM_DEBUG_ZEBRA) {
char source_str[100];
char group_str[100];
char source_str[INET_ADDRSTRLEN];
char group_str[INET_ADDRSTRLEN];
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));
zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
__FILE__, __PRETTY_FUNCTION__,
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 */
old_vif_index = c_oil->oil.mfcc_parent;
c_oil->oil.mfcc_parent = input_iface_vif_index;
zlog_debug ("FF");
/* update kernel multicast forwarding cache (MFC) */
if (pim_mroute_add(c_oil))
if (pim_mroute_add(c_oil, __PRETTY_FUNCTION__))
{
/* just log warning */
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);
char source_str[100];
char group_str[100];
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));
zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
__FILE__, __PRETTY_FUNCTION__,
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);
if (PIM_DEBUG_MROUTE)
{
/* just log warning */
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);
char source_str[INET_ADDRSTRLEN];
char group_str[INET_ADDRSTRLEN];
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));
zlog_debug("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
__FILE__, __PRETTY_FUNCTION__,
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_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);
}
static int on_rpf_cache_refresh(struct thread *t)
{
zassert(t);
zassert(qpim_rpf_cache_refresher);
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_events;
pim_rp_setup ();
return 0;
}
static void sched_rpf_cache_refresh()
void sched_rpf_cache_refresh(void)
{
++qpim_rpf_cache_refresh_requests;
pim_rpf_set_refresh_time ();
if (qpim_rpf_cache_refresher) {
/* Refresh timer is already running */
return;
@ -575,17 +632,6 @@ static int redist_read_ipv4_route(int command, struct zclient *zclient,
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. */
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();
pim_rp_setup ();
return 0;
}
@ -662,6 +709,7 @@ pim_zebra_connected (struct zclient *zclient)
{
zclient_send_reg_requests (zclient, VRF_DEFAULT);
}
void pim_zebra_init(char *zebra_sock_path)
{
int i;
@ -719,9 +767,7 @@ void pim_zebra_init(char *zebra_sock_path)
__PRETTY_FUNCTION__);
}
zassert(!qpim_zclient_lookup);
qpim_zclient_lookup = zclient_lookup_new();
zassert(qpim_zclient_lookup);
zclient_lookup_new();
}
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)
{
struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE];
struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
int num_ifindex;
int vif_index;
ifindex_t first_ifindex;
num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr,
num_ifindex = zclient_lookup_nexthop(nexthop_tab,
MULTIPATH_NUM, addr,
PIM_NEXTHOP_LOOKUP_MAX);
if (num_ifindex < 1) {
char addr_str[100];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_warn("%s %s: could not find nexthop ifindex for address %s",
__FILE__, __PRETTY_FUNCTION__,
addr_str);
if (PIM_DEBUG_ZEBRA)
{
char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s %s: could not find nexthop ifindex for address %s",
__FILE__, __PRETTY_FUNCTION__,
addr_str);
}
return -1;
}
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);
if (PIM_DEBUG_ZEBRA)
{
char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
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 */
}
if (PIM_DEBUG_ZEBRA) {
char addr_str[100];
char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
__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);
if (vif_index < 0) {
char addr_str[100];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
__FILE__, __PRETTY_FUNCTION__,
vif_index, addr_str);
if (PIM_DEBUG_ZEBRA)
{
char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s %s: low vif_index=%d < 1 nexthop for address %s",
__FILE__, __PRETTY_FUNCTION__,
vif_index, addr_str);
}
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;
}
@ -828,17 +866,11 @@ static int del_oif(struct channel_oil *channel_oil,
struct pim_interface *pim_ifp;
int old_ttl;
zassert(channel_oil);
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) {
char group_str[100];
char source_str[100];
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",
@ -850,15 +882,18 @@ static int del_oif(struct channel_oil *channel_oil,
/* Prevent single protocol from unsubscribing same interface from
channel (S,G) multiple times */
if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
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_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
__FILE__, __PRETTY_FUNCTION__,
proto_mask, oif->name, pim_ifp->mroute_vif_index,
channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
source_str, group_str);
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: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
__FILE__, __PRETTY_FUNCTION__,
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;
}
@ -873,15 +908,18 @@ static int del_oif(struct channel_oil *channel_oil,
/* Check the OIF keeps existing before returning, and only log
warning otherwise */
if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
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_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
__FILE__, __PRETTY_FUNCTION__,
proto_mask, oif->name, pim_ifp->mroute_vif_index,
channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
source_str, group_str);
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: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
__FILE__, __PRETTY_FUNCTION__,
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;
@ -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];
if (old_ttl < 1) {
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_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
__FILE__, __PRETTY_FUNCTION__,
oif->name, pim_ifp->mroute_vif_index,
source_str, group_str);
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: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
__FILE__, __PRETTY_FUNCTION__,
oif->name, pim_ifp->mroute_vif_index,
source_str, group_str);
}
return -3;
}
channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
if (pim_mroute_add(channel_oil)) {
char group_str[100];
char source_str[100];
if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) {
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_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;
if (channel_oil->oil_size < 1) {
if (pim_mroute_del(channel_oil)) {
/* just log a warning in case of failure */
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_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
__FILE__, __PRETTY_FUNCTION__,
source_str, group_str);
if (pim_mroute_del(channel_oil, __PRETTY_FUNCTION__)) {
if (PIM_DEBUG_MROUTE)
{
/* just log a warning in case of failure */
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: failure removing OIL for channel (S,G)=(%s,%s)",
__FILE__, __PRETTY_FUNCTION__,
source_str, group_str);
}
}
}
if (PIM_DEBUG_MROUTE) {
char group_str[100];
char source_str[100];
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: DONE",
@ -949,16 +993,17 @@ static int del_oif(struct channel_oil *channel_oil,
void igmp_source_forward_start(struct igmp_source *source)
{
struct igmp_group *group;
struct prefix_sg sg;
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) {
char source_str[100];
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",
zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
__PRETTY_FUNCTION__,
source_str, group_str,
pim_str_sg_dump (&sg),
source->source_group->group_igmp_sock->fd,
source->source_group->group_igmp_sock->interface->name,
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 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;
int input_iface_vif_index = fib_lookup_if_vif_index(vif_source);
if (input_iface_vif_index < 1) {
char source_str[100];
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
zlog_warn("%s %s: could not find input interface for source %s",
__FILE__, __PRETTY_FUNCTION__,
source_str);
if (PIM_DEBUG_IGMP_TRACE)
{
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
zlog_debug("%s %s: could not find input interface for source %s",
__FILE__, __PRETTY_FUNCTION__,
source_str);
}
return;
}
@ -996,28 +1044,21 @@ void igmp_source_forward_start(struct igmp_source *source)
*/
pim_oif = source->source_group->group_igmp_sock->interface->info;
if (!pim_oif) {
zlog_warn("%s: multicast not enabled on oif=%s ?",
__PRETTY_FUNCTION__,
source->source_group->group_igmp_sock->interface->name);
return;
}
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);
if (PIM_DEBUG_IGMP_TRACE)
{
zlog_debug("%s: multicast not enabled on oif=%s ?",
__PRETTY_FUNCTION__,
source->source_group->group_igmp_sock->interface->name);
}
return;
}
if (input_iface_vif_index == pim_oif->mroute_vif_index) {
/* ignore request for looped MFC entry */
if (PIM_DEBUG_IGMP_TRACE) {
char source_str[100];
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",
zlog_debug("%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
__PRETTY_FUNCTION__,
source_str, group_str,
pim_str_sg_dump (&sg),
source->source_group->group_igmp_sock->fd,
source->source_group->group_igmp_sock->interface->name,
input_iface_vif_index);
@ -1025,17 +1066,15 @@ void igmp_source_forward_start(struct igmp_source *source)
return;
}
source->source_channel_oil = pim_channel_oil_add(group->group_addr,
source->source_addr,
source->source_channel_oil = pim_channel_oil_add(&sg,
input_iface_vif_index);
if (!source->source_channel_oil) {
char group_str[100];
char source_str[100];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
__FILE__, __PRETTY_FUNCTION__,
source_str, group_str);
if (PIM_DEBUG_IGMP_TRACE)
{
zlog_debug("%s %s: could not create OIL for channel (S,G)=%s",
__FILE__, __PRETTY_FUNCTION__,
pim_str_sg_dump (&sg));
}
return;
}
}
@ -1044,8 +1083,11 @@ void igmp_source_forward_start(struct igmp_source *source)
group->group_igmp_sock->interface,
PIM_OIF_FLAG_PROTO_IGMP);
if (result) {
zlog_warn("%s: add_oif() failed with return=%d",
__func__, result);
if (PIM_DEBUG_MROUTE)
{
zlog_warn("%s: add_oif() failed with return=%d",
__func__, result);
}
return;
}
@ -1053,8 +1095,7 @@ void igmp_source_forward_start(struct igmp_source *source)
Feed IGMPv3-gathered local membership information into PIM
per-interface (S,G) state.
*/
pim_ifchannel_local_membership_add(group->group_igmp_sock->interface,
source->source_addr, group->group_addr);
pim_ifchannel_local_membership_add(group->group_igmp_sock->interface, &sg);
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)
{
struct igmp_group *group;
struct prefix_sg sg;
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) {
char source_str[100];
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",
zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
__PRETTY_FUNCTION__,
source_str, group_str,
pim_str_sg_dump (&sg),
source->source_group->group_igmp_sock->fd,
source->source_group->group_igmp_sock->interface->name,
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,
PIM_OIF_FLAG_PROTO_IGMP);
if (result) {
zlog_warn("%s: del_oif() failed with return=%d",
__func__, result);
if (PIM_DEBUG_IGMP_TRACE)
zlog_debug("%s: del_oif() failed with return=%d",
__func__, result);
return;
}
@ -1114,7 +1157,7 @@ void igmp_source_forward_stop(struct igmp_source *source)
per-interface (S,G) state.
*/
pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
source->source_addr, group->group_addr);
&sg);
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;
if (PIM_DEBUG_PIM_TRACE) {
char source_str[100];
char group_str[100];
char upstream_str[100];
char source_str[INET_ADDRSTRLEN];
char group_str[INET_ADDRSTRLEN];
char upstream_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", ch->sg.src, source_str, sizeof(source_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));
zlog_debug("%s: (S,G)=(%s,%s) oif=%s(%s)",
__PRETTY_FUNCTION__,
@ -1139,24 +1182,24 @@ void pim_forward_start(struct pim_ifchannel *ch)
if (!up->channel_oil) {
int input_iface_vif_index = fib_lookup_if_vif_index(up->upstream_addr);
if (input_iface_vif_index < 1) {
char source_str[100];
pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
zlog_warn("%s %s: could not find input interface for source %s",
__FILE__, __PRETTY_FUNCTION__,
source_str);
if (PIM_DEBUG_PIM_TRACE)
{
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", up->sg.src, source_str, sizeof(source_str));
zlog_debug("%s %s: could not find input interface for source %s",
__FILE__, __PRETTY_FUNCTION__,
source_str);
}
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);
if (!up->channel_oil) {
char group_str[100];
char source_str[100];
pim_inet4_dump("<group?>", up->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
__FILE__, __PRETTY_FUNCTION__,
source_str, group_str);
if (PIM_DEBUG_PIM_TRACE)
zlog_debug("%s %s: could not create OIL for channel (S,G)=%s",
__FILE__, __PRETTY_FUNCTION__,
up->sg_str);
return;
}
}
@ -1171,23 +1214,16 @@ void pim_forward_stop(struct pim_ifchannel *ch)
struct pim_upstream *up = ch->upstream;
if (PIM_DEBUG_PIM_TRACE) {
char source_str[100];
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",
zlog_debug("%s: (S,G)=%s oif=%s",
__PRETTY_FUNCTION__,
source_str, group_str, ch->interface->name);
ch->sg_str, ch->interface->name);
}
if (!up->channel_oil) {
char source_str[100];
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_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
__PRETTY_FUNCTION__,
source_str, group_str, ch->interface->name);
if (PIM_DEBUG_PIM_TRACE)
zlog_debug("%s: (S,G)=%s oif=%s missing channel OIL",
__PRETTY_FUNCTION__,
ch->sg_str, ch->interface->name);
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_stop(struct pim_ifchannel *ch);
void sched_rpf_cache_refresh(void);
#endif /* PIM_ZEBRA_H */

View File

@ -27,13 +27,17 @@
#include "stream.h"
#include "network.h"
#include "thread.h"
#include "prefix.h"
#include "vty.h"
#include "pimd.h"
#include "pim_iface.h"
#include "pim_pim.h"
#include "pim_str.h"
#include "pim_oil.h"
#include "pim_zlookup.h"
extern int zclient_debug;
static struct zclient *zlookup = NULL;
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);
}
struct zclient *zclient_lookup_new()
void
zclient_lookup_new (void)
{
struct zclient *zlookup;
zlookup = zclient_new (master);
if (!zlookup) {
zlog_err("%s: zclient_new() failure",
__PRETTY_FUNCTION__);
return 0;
return;
}
zlookup->sock = -1;
@ -137,7 +140,6 @@ struct zclient *zclient_lookup_new()
zlog_notice("%s: zclient lookup socket initialized",
__PRETTY_FUNCTION__);
return 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 i, err;
if (PIM_DEBUG_ZEBRA) {
char addr_str[100];
if (PIM_DEBUG_PIM_TRACE_DETAIL) {
char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s: addr=%s",
__PRETTY_FUNCTION__,
@ -192,8 +194,8 @@ static int zclient_read_nexthop(struct zclient *zlookup,
raddr.s_addr = stream_get_ipv4(s);
if (raddr.s_addr != addr.s_addr) {
char addr_str[100];
char raddr_str[100];
char addr_str[INET_ADDRSTRLEN];
char raddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
pim_inet4_dump("<raddr?>", raddr, raddr_str, sizeof(raddr_str));
zlog_warn("%s: address mismatch: addr=%s raddr=%s",
@ -212,77 +214,52 @@ static int zclient_read_nexthop(struct zclient *zlookup,
return -6;
}
length -= MIN_LEN;
for (i = 0; i < nexthop_num; ++i) {
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);
--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) {
case NEXTHOP_TYPE_IFINDEX:
case NEXTHOP_TYPE_IPV4_IFINDEX:
if (num_ifindex >= tab_size) {
char addr_str[100];
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;
}
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;
case NEXTHOP_TYPE_IPV4:
nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET;
if (nexthop_type == NEXTHOP_TYPE_IPV4_IFINDEX ||
nexthop_type == NEXTHOP_TYPE_IPV4) {
nexthop_tab[num_ifindex].nexthop_addr.u.prefix4.s_addr = stream_get_ipv4(s);
}
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].protocol_distance = distance;
nexthop_tab[num_ifindex].route_metric = metric;
++num_ifindex;
break;
case NEXTHOP_TYPE_IPV4:
if (num_ifindex >= tab_size) {
char addr_str[100];
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;
}
nexthop_tab[num_ifindex].nexthop_addr.s_addr = stream_get_ipv4(s);
length -= 4;
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;
case NEXTHOP_TYPE_IPV6_IFINDEX:
nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET6;
stream_get (&nexthop_tab[num_ifindex].nexthop_addr.u.prefix6, s, 16);
nexthop_tab[num_ifindex].ifindex = stream_getl (s);
nbr = pim_neighbor_find_if (if_lookup_by_index_vrf (nexthop_tab[num_ifindex].ifindex, VRF_DEFAULT));
if (nbr)
{
nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET;
nexthop_tab[num_ifindex].nexthop_addr.u.prefix4 = nbr->source_addr;
}
++num_ifindex;
break;
default:
/* do nothing */
{
char addr_str[100];
char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_warn("%s %s: found non-ifindex nexthop type=%d for address %s",
__FILE__, __PRETTY_FUNCTION__,
@ -295,16 +272,16 @@ static int zclient_read_nexthop(struct zclient *zlookup,
return num_ifindex;
}
static int zclient_lookup_nexthop_once(struct zclient *zlookup,
struct pim_zlookup_nexthop nexthop_tab[],
const int tab_size,
struct in_addr addr)
static int
zclient_lookup_nexthop_once (struct pim_zlookup_nexthop nexthop_tab[],
const int tab_size,
struct in_addr addr)
{
struct stream *s;
int ret;
if (PIM_DEBUG_ZEBRA) {
char addr_str[100];
if (PIM_DEBUG_PIM_TRACE_DETAIL) {
char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s: addr=%s",
__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));
if (ret < 0) {
zlog_err("%s %s: writen() failure writing to zclient lookup socket",
__FILE__, __PRETTY_FUNCTION__);
zlog_err("%s %s: writen() failure: %d writing to zclient lookup socket",
__FILE__, __PRETTY_FUNCTION__, errno);
zclient_lookup_failed(zlookup);
return -2;
}
@ -343,26 +320,28 @@ static int zclient_lookup_nexthop_once(struct zclient *zlookup,
tab_size, addr);
}
int zclient_lookup_nexthop(struct zclient *zlookup,
struct pim_zlookup_nexthop nexthop_tab[],
const int tab_size,
struct in_addr addr,
int max_lookup)
int
zclient_lookup_nexthop (struct pim_zlookup_nexthop nexthop_tab[],
const int tab_size,
struct in_addr addr,
int max_lookup)
{
int lookup;
uint32_t route_metric = 0xFFFFFFFF;
uint8_t protocol_distance = 0xFF;
qpim_nexthop_lookups++;
for (lookup = 0; lookup < max_lookup; ++lookup) {
int num_ifindex;
int first_ifindex;
struct in_addr nexthop_addr;
struct prefix nexthop_addr;
num_ifindex = zclient_lookup_nexthop_once(qpim_zclient_lookup, nexthop_tab,
PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr);
num_ifindex = zclient_lookup_nexthop_once(nexthop_tab,
tab_size, addr);
if (num_ifindex < 1) {
if (PIM_DEBUG_ZEBRA) {
char addr_str[100];
char addr_str[INET_ADDRSTRLEN];
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",
__FILE__, __PRETTY_FUNCTION__,
@ -378,9 +357,13 @@ int zclient_lookup_nexthop(struct zclient *zlookup,
}
/*
FIXME: Non-recursive nexthop ensured only for first ifindex.
However, recursive route lookup should really be fixed in zebra daemon.
See also TODO T24.
* FIXME: Non-recursive nexthop ensured only for first ifindex.
* However, recursive route lookup should really be fixed in zebra daemon.
* 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;
nexthop_addr = nexthop_tab[0].nexthop_addr;
@ -390,7 +373,7 @@ int zclient_lookup_nexthop(struct zclient *zlookup,
if (lookup > 0) {
/* Report non-recursive success after first lookup */
if (PIM_DEBUG_ZEBRA) {
char addr_str[100];
char addr_str[INET_ADDRSTRLEN];
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",
__FILE__, __PRETTY_FUNCTION__,
@ -400,7 +383,7 @@ int zclient_lookup_nexthop(struct zclient *zlookup,
}
/* 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 */
nexthop_tab[0].route_metric = route_metric;
@ -411,10 +394,10 @@ int zclient_lookup_nexthop(struct zclient *zlookup,
}
if (PIM_DEBUG_ZEBRA) {
char addr_str[100];
char nexthop_str[100];
char addr_str[INET_ADDRSTRLEN];
char nexthop_str[PREFIX_STRLEN];
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",
__FILE__, __PRETTY_FUNCTION__,
lookup, max_lookup, nexthop_str, addr_str,
@ -422,12 +405,12 @@ int zclient_lookup_nexthop(struct zclient *zlookup,
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) */
if (PIM_DEBUG_ZEBRA) {
char addr_str[100];
char addr_str[INET_ADDRSTRLEN];
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",
__FILE__, __PRETTY_FUNCTION__,
@ -436,3 +419,100 @@ int zclient_lookup_nexthop(struct zclient *zlookup,
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 */
struct pim_zlookup_nexthop {
struct in_addr nexthop_addr;
struct prefix nexthop_addr;
ifindex_t ifindex;
uint32_t route_metric;
uint8_t protocol_distance;
};
struct zclient *zclient_lookup_new(void);
void zclient_lookup_new (void);
int zclient_lookup_nexthop(struct zclient *zlookup,
struct pim_zlookup_nexthop nexthop_tab[],
int zclient_lookup_nexthop(struct pim_zlookup_nexthop nexthop_tab[],
const int tab_size,
struct in_addr addr,
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 */

View File

@ -23,6 +23,9 @@
#include "log.h"
#include "memory.h"
#include "if.h"
#include "prefix.h"
#include "vty.h"
#include "plist.h"
#include "pimd.h"
#include "pim_cmd.h"
@ -35,6 +38,7 @@
#include "pim_rpf.h"
#include "pim_ssmpingd.h"
#include "pim_static.h"
#include "pim_rp.h"
const char *const PIM_ALL_SYSTEMS = MCAST_ALL_SYSTEMS;
const char *const PIM_ALL_ROUTERS = MCAST_ALL_ROUTERS;
@ -45,21 +49,17 @@ struct thread_master *master = NULL;
uint32_t qpim_debugs = 0;
int qpim_mroute_socket_fd = -1;
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;
struct list *qpim_channel_oil_list = 0;
int qpim_t_periodic = PIM_DEFAULT_T_PERIODIC; /* Period between Join/Prune Messages */
struct list *qpim_upstream_list = 0;
struct zclient *qpim_zclient_update = 0;
struct zclient *qpim_zclient_lookup = 0;
struct zclient *qpim_zclient_update = NULL;
struct pim_assert_metric qpim_infinite_assert_metric;
long qpim_rpf_cache_refresh_delay_msec = 10000;
struct thread *qpim_rpf_cache_refresher = 0;
long qpim_rpf_cache_refresh_delay_msec = 50;
struct thread *qpim_rpf_cache_refresher = NULL;
int64_t qpim_rpf_cache_refresh_requests = 0;
int64_t qpim_rpf_cache_refresh_events = 0;
int64_t qpim_rpf_cache_refresh_last = 0;
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;
int64_t qpim_scan_oil_events = 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_del_events = 0;
int64_t qpim_mroute_del_last = 0;
struct list *qpim_static_route_list = 0;
struct pim_rpf qpim_rp = { .rpf_addr.s_addr = INADDR_NONE };
struct list *qpim_static_route_list = NULL;
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_probe_time = PIM_REGISTER_PROBE_TIME_DEFAULT;
@ -77,22 +80,28 @@ static void pim_free()
{
pim_ssmpingd_destroy();
if (qpim_channel_oil_list)
list_free(qpim_channel_oil_list);
pim_oil_terminate ();
if (qpim_upstream_list)
list_free(qpim_upstream_list);
pim_upstream_terminate ();
if (qpim_static_route_list)
list_free(qpim_static_route_list);
pim_route_map_terminate();
pim_if_terminate ();
pim_rp_free ();
pim_route_map_terminate();
}
void pim_init()
{
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)) {
zlog_err("%s %s: could not solve %s to group address: errno=%d: %s",
__FILE__, __PRETTY_FUNCTION__,
@ -101,22 +110,9 @@ void pim_init()
return;
}
qpim_channel_oil_list = list_new();
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;
pim_oil_init ();
qpim_upstream_list = list_new();
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;
pim_upstream_init ();
qpim_static_route_list = list_new();
if (!qpim_static_route_list) {
@ -129,9 +125,6 @@ void pim_init()
qpim_mroute_socket_fd = -1; /* mark mroute as disabled */
qpim_mroute_oif_highest_vif_index = -1;
zassert(!qpim_debugs);
zassert(!PIM_MROUTE_IS_ENABLED);
qpim_inaddr_any.s_addr = PIM_NET_INADDR_ANY;
/*

View File

@ -23,13 +23,13 @@
#include <stdint.h>
#include "pim_str.h"
#include "pim_memory.h"
#include "pim_assert.h"
#define PIMD_PROGNAME "pimd"
#define PIMD_DEFAULT_CONFIG "pimd.conf"
#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_MAX_LEN (60)
@ -51,6 +51,8 @@
#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 max(x,y) ((x) > (y) ? (x) : (y))
#define PIM_MASK_PIM_EVENTS (1 << 0)
#define PIM_MASK_PIM_EVENTS_DETAIL (1 << 1)
#define PIM_MASK_PIM_PACKETS (1 << 2)
@ -65,9 +67,28 @@
#define PIM_MASK_ZEBRA (1 << 11)
#define PIM_MASK_SSMPINGD (1 << 12)
#define PIM_MASK_MROUTE (1 << 13)
#define PIM_MASK_PIM_HELLO (1 << 14)
#define PIM_MASK_PIM_J_P (1 << 15)
#define PIM_MASK_STATIC (1 << 16)
#define PIM_MASK_MROUTE_DETAIL (1 << 14)
#define PIM_MASK_PIM_HELLO (1 << 15)
#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_ROUTERS;
@ -78,14 +99,10 @@ extern struct thread_master *master;
uint32_t qpim_debugs;
int qpim_mroute_socket_fd;
int64_t qpim_mroute_socket_creation; /* timestamp of creation */
struct thread *qpim_mroute_socket_reader;
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;
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_lookup;
struct pim_assert_metric qpim_infinite_assert_metric;
long qpim_rpf_cache_refresh_delay_msec;
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_del_events;
int64_t qpim_mroute_del_last;
int64_t qpim_nexthop_lookups;
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)
@ -132,12 +153,17 @@ extern int32_t qpim_register_probe_time;
#define PIM_DEBUG_ZEBRA (qpim_debugs & PIM_MASK_ZEBRA)
#define PIM_DEBUG_SSMPINGD (qpim_debugs & PIM_MASK_SSMPINGD)
#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_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_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_PACKETS (qpim_debugs & (PIM_MASK_PIM_PACKETS | PIM_MASK_IGMP_PACKETS))
#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 | PIM_MASK_MSDP_PACKETS))
#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)
@ -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_SSMPINGD (qpim_debugs |= PIM_MASK_SSMPINGD)
#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_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_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_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_SSMPINGD (qpim_debugs &= ~PIM_MASK_SSMPINGD)
#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_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_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_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 \
$(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 \
$(protobuf_srcs) \
$(protobuf_srcs) zebra_mroute.c \
$(dev_srcs)
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 \
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 \
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)

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) \
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_terminate (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 mpls_kernel_init (void);
extern int kernel_get_ipmr_sg_stats (void *mroute);
#endif /* _ZEBRA_RT_H */

View File

@ -55,6 +55,8 @@
#include "zebra/zebra_mpls.h"
#include "zebra/kernel_netlink.h"
#include "zebra/rt_netlink.h"
#include "zebra/zebra_mroute.h"
/* TODO - Temporary definitions, need to refine. */
#ifndef AF_MPLS
@ -88,6 +90,10 @@
#ifndef MPLS_IPTUNNEL_DST
#define MPLS_IPTUNNEL_DST 1
#endif
#ifndef NDA_MASTER
#define NDA_MASTER 9
#endif
/* End of temporary definitions */
struct gw_family_t
@ -520,15 +526,17 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
return 0;
}
static struct mcast_route_data *mroute = NULL;
static int
netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
ns_id_t ns_id)
{
int len;
unsigned long long lastused = 0;
struct rtmsg *rtm;
struct rtattr *tb[RTA_MAX + 1];
struct prefix_sg sg;
struct mcast_route_data *m;
struct mcast_route_data mr;
int iif = 0;
int count;
int oif[256];
@ -536,10 +544,16 @@ netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h
char sbuf[40];
char gbuf[40];
char oif_list[256] = "\0";
memset (&sg, 0, sizeof (sg));
sg.family = IANA_AFI_IPMR;
vrf_id_t vrf = ns_id;
if (mroute)
m = mroute;
else
{
memset (&mr, 0, sizeof (mr));
m = &mr;
}
rtm = NLMSG_DATA (h);
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]);
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])
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])
lastused = *(unsigned long long *)RTA_DATA (tb[RTA_EXPIRES]);
m->lastused = *(unsigned long long *)RTA_DATA (tb[RTA_EXPIRES]);
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)
{
strcpy (sbuf, inet_ntoa (sg.src));
strcpy (gbuf, inet_ntoa (sg.grp));
struct interface *ifp;
strcpy (sbuf, inet_ntoa (m->sg.src));
strcpy (gbuf, inet_ntoa (m->sg.grp));
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];
sprintf (temp, "%s ", ifp->name);
strcat (oif_list, temp);
}
zlog_debug ("MCAST %s (%s,%s) IIF: %d OIF: %s jiffies: %lld",
nl_msg_type_to_str (h->nlmsg_type), sbuf, gbuf, iif, oif_list, lastused);
ifp = if_lookup_by_index_vrf (iif, vrf);
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;
}
@ -1509,6 +1525,39 @@ skip:
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
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 */
return 0;
}
extern int
kernel_get_ipmr_sg_stats (void *mroute)
{
return 0;
}

View File

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