sudo yum install git autoconf automake libtool make gawk readline-devel \
texinfo net-snmp-devel groff pkgconfig json-c-devel pam-devel \
- flex pytest
+ flex c-ares-devel epel-release
Install newer version of bison (CentOS 6 package source is too old) from
CentOS 7
Install `Python 2.7` in parallel to default 2.6 (needed for `make check` to
run unittests).
-Pick correct EPEL based on CentOS version used. Then install current `pytest`
+Make sure you've install EPEL (`epel-release` as above). Then install current
+`python2.7` and `pytest`
- rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
rpm -ivh https://centos6.iuscommunity.org/ius-release.rpm
- yum install python27 python27-pip
+ yum install python27 python27-devel python27-pip
pip2.7 install pytest
Please note that `CentOS 6` needs to keep python pointing to version 2.6
for `yum` to keep working, so don't create a symlink for python2.7 to python
-
+
Get FRR, compile it and install it (from Git)
---------------------------------------------
git clone https://github.com/freerangerouting/frr.git frr
cd frr
- git checkout stable/2.0
./bootstrap.sh
./configure \
--sysconfdir=/etc/frr \
Install required packages
-------------------------
-
+
Add packages:
sudo yum install git autoconf automake libtool make gawk readline-devel \
texinfo net-snmp-devel groff pkgconfig json-c-devel pam-devel \
- bison flex pytest
+ bison flex pytest c-ares-devel python-devel
+
+To build from git (in difference to building from distribution tar.gz as created by `make dist`), the python development libraries are needed. (Make sure you've installed EPEL libraries as shown above for this to work)
+
+ yum install python34-devel
Get FRR, compile it and install it (from Git)
---------------------------------------------
git clone https://github.com/freerangerouting/frr.git frr
cd frr
- git checkout stable/2.0
./bootstrap.sh
./configure \
--sysconfdir=/etc/frr \
Install required packages
-------------------------
-
+
Add packages:
sudo apt-get install git autoconf automake libtool make gawk \
libreadline-dev texinfo libjson-c-dev pkg-config bison flex \
- python-pip
+ python-pip libc-ares-dev python3-dev
Install newer pytest (>3.0) from pip
git clone https://github.com/freerangerouting/frr.git frr
cd frr
- git checkout stable/2.0
./bootstrap.sh
./configure \
--enable-exampledir=/usr/share/doc/frr/examples/ \
sudo dnf install git autoconf automake libtool make gawk \
readline-devel texinfo net-snmp-devel groff pkgconfig \
- json-c-devel pam-devel perl-XML-LibXML pytest
+ json-c-devel pam-devel perl-XML-LibXML c-ares-devel \
+ python3-devel
Get FRR, compile it and install it (from Git)
---------------------------------------------
git clone https://github.com/freerangerouting/frr.git frr
cd frr
- git checkout stable/2.0
./bootstrap.sh
./configure \
--sysconfdir=/etc/frr \
install and asked)
pkg install git autoconf automake libtool gmake gawk json-c pkgconf \
- bison flex py27-pytest
+ bison flex py27-pytest c-ares python3
Make sure there is no /usr/bin/flex preinstalled (and use the newly
installed in /usr/local/bin):
git clone https://github.com/freerangerouting/frr.git frr
cd frr
- git checkout stable/2.0
./bootstrap.sh
export MAKE=gmake
export LDFLAGS="-L/usr/local/lib"
install and asked)
pkg install git autoconf automake libtool gmake gawk json-c pkgconf \
- bison flex py27-pytest
+ bison flex py27-pytest c-ares python3
Make sure there is no /usr/bin/flex preinstalled (and use the newly
installed in /usr/local/bin):
git clone https://github.com/freerangerouting/frr.git frr
cd frr
- git checkout stable/2.0
./bootstrap.sh
export MAKE=gmake
export LDFLAGS="-L/usr/local/lib"
install and asked)
pkg install -y git autoconf automake libtool gmake gawk \
- pkgconf texinfo json-c bison flex py27-pytest
+ pkgconf texinfo json-c bison flex py27-pytest c-ares \
+ python3
Make sure there is no /usr/bin/flex preinstalled (and use the newly
installed in /usr/local/bin):
rm -f /usr/bin/flex
+For building with clang (instead of gcc), upgrade clang from 3.4 default to 3.6 *This is needed to build FreeBSD packages as well - for packages clang is default* (Clang 3.4 as shipped with FreeBSD 9 crashes during compile)
+
+ pkg install clang36
+ pkg delete clang34
+ mv /usr/bin/clang /usr/bin/clang34
+ ln -s /usr/local/bin/clang36 /usr/bin/clang
+
Get FRR, compile it and install it (from Git)
---------------------------------------------
git clone https://github.com/freerangerouting/frr.git frr
cd frr
- git checkout stable/2.0
./bootstrap.sh
export MAKE=gmake
export LDFLAGS="-L/usr/local/lib"
Add packages:
sudo pkg_add git autoconf automake libtool gmake gawk openssl \
- pkg-config json-c p5-XML-LibXML python27 py27-test
+ pkg-config json-c p5-XML-LibXML python27 py27-test python35
Install SSL Root Certificates (for git https access):
git clone https://github.com/freerangerouting/frr.git frr
cd frr
- git checkout stable/2.0
./bootstrap.sh
MAKE=gmake
export LDFLAGS="-L/usr/pkg/lib -R/usr/pkg/lib"
-------------------------
sudo pkgin install git autoconf automake libtool gmake gawk openssl \
- pkg-config json-c p5-XML-LibXML python27 py27-test
+ pkg-config json-c p5-XML-LibXML python27 py27-test python35
Install SSL Root Certificates (for git https access):
git clone https://github.com/freerangerouting/frr.git frr
cd frr
- git checkout stable/2.0
./bootstrap.sh
MAKE=gmake
export LDFLAGS="-L/usr/pkg/lib -R/usr/pkg/lib"
/opt/csw/bin/pkgutil -y -i texinfo
/opt/csw/bin/pkgutil -y -i perl
/opt/csw/bin/pkgutil -y -i libjson_c_dev
- /opt/csw/bin/pkgutil -y -i python27 py_pip
+ /opt/csw/bin/pkgutil -y -i python27 py_pip python27_dev
Add libjson to Solaris equivalent of ld.so.conf
rm -f /usr/bin/python
ln -s /opt/csw/bin/python2.7 /usr/bin/python
-
+
Fix PATH for all users and non-interactive sessions. Edit `/etc/default/login`
and add the following default PATH:
git clone https://github.com/freerangerouting/frr.git frr
cd frr
- git checkout stable/2.0
./bootstrap.sh
export MAKE=gmake
export LDFLAGS="-L/opt/csw/lib"
export CPPFLAGS="-I/opt/csw/include"
+ export PKG_CONFIG_PATH=/opt/csw/lib/pkgconfig
./configure \
--sysconfdir=/etc/frr \
--enable-exampledir=/usr/share/doc/frr/examples/ \
git clone https://github.com/freerangerouting/frr.git frr
cd frr
- git checkout stable/2.0
./bootstrap.sh
export LDFLAGS="-L/usr/local/lib"
export CPPFLAGS="-I/usr/local/include"
Add packages:
apt-get install git autoconf automake libtool make gawk libreadline-dev \
- texinfo libpam0g-dev dejagnu libjson0 pkg-config libpam0g-dev \
- libjson0-dev flex python-pip
+ texinfo libpam0g-dev dejagnu libjson0-dev pkg-config libpam0g-dev \
+ libjson0-dev flex python-pip libc-ares-dev python3-dev
Install newer bison from 14.04 package source (Ubuntu 12.04 package source
is too old)
git clone https://github.com/freerangerouting/frr.git frr
cd frr
- git checkout stable/2.0
./bootstrap.sh
./configure \
--enable-exampledir=/usr/share/doc/frr/examples/ \
Install required packages
-------------------------
-
+
Add packages:
apt-get install git autoconf automake libtool make gawk libreadline-dev \
texinfo dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex \
- python-pytest
+ python-pytest libc-ares-dev python3-dev
Get FRR, compile it and install it (from Git)
---------------------------------------------
git clone https://github.com/freerangerouting/frr.git frr
cd frr
- git checkout stable/2.0
./bootstrap.sh
./configure \
--enable-exampledir=/usr/share/doc/frr/examples/ \
apt-get install git autoconf automake libtool make gawk libreadline-dev \
texinfo dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex \
- python-pytest
+ python-pytest libc-ares-dev python3-dev
Get FRR, compile it and install it (from Git)
---------------------------------------------
git clone https://github.com/freerangerouting/frr.git frr
cd frr
- git checkout stable/2.0
./bootstrap.sh
./configure \
--enable-exampledir=/usr/share/doc/frr/examples/ \
pim_ssmpingd.c pim_int.c pim_rp.c \
pim_static.c pim_br.c pim_register.c pim_routemap.c \
pim_msdp.c pim_msdp_socket.c pim_msdp_packet.c \
- pim_jp_agg.c pim_nht.c
+ pim_jp_agg.c pim_nht.c pim_ssm.c
noinst_HEADERS = \
pim_memory.h \
pim_igmp_join.h pim_ssmpingd.h pim_int.h pim_rp.h \
pim_static.h pim_br.h pim_register.h \
pim_msdp.h pim_msdp_socket.h pim_msdp_packet.h pim_nht.h \
- pim_jp_agg.h
+ pim_jp_agg.h pim_ssm.h
pimd_SOURCES = \
pim_main.c $(libpim_a_SOURCES)
#include "pim_rp.h"
#include "pim_zlookup.h"
#include "pim_msdp.h"
+#include "pim_ssm.h"
static struct cmd_node pim_global_node = {
PIM_NODE,
return pim_no_rp_cmd_worker (vty, argv[4]->arg, NULL, argv[6]->arg);
}
+static int
+pim_ssm_cmd_worker (struct vty *vty, const char *plist)
+{
+ int result = pim_ssm_range_set (VRF_DEFAULT, plist);
+
+ if (result == PIM_SSM_ERR_NONE)
+ return CMD_SUCCESS;
+
+ switch (result)
+ {
+ case PIM_SSM_ERR_NO_VRF:
+ vty_out (vty, "%% VRF doesn't exist%s", VTY_NEWLINE);
+ break;
+ case PIM_SSM_ERR_DUP:
+ vty_out (vty, "%% duplicate config%s", VTY_NEWLINE);
+ break;
+ default:
+ vty_out (vty, "%% ssm range config failed%s", VTY_NEWLINE);
+ }
+
+ return CMD_WARNING;
+}
+
+DEFUN (ip_pim_ssm_prefix_list,
+ ip_pim_ssm_prefix_list_cmd,
+ "ip pim ssm prefix-list WORD",
+ IP_STR
+ "pim multicast routing\n"
+ "Source Specific Multicast\n"
+ "group range prefix-list filter\n"
+ "Name of a prefix-list\n")
+{
+ return pim_ssm_cmd_worker (vty, argv[0]->arg);
+}
+
+DEFUN (no_ip_pim_ssm_prefix_list,
+ no_ip_pim_ssm_prefix_list_cmd,
+ "no ip pim ssm prefix-list",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Source Specific Multicast\n"
+ "group range prefix-list filter\n")
+{
+ return pim_ssm_cmd_worker (vty, NULL);
+}
+
+DEFUN (no_ip_pim_ssm_prefix_list_name,
+ no_ip_pim_ssm_prefix_list_name_cmd,
+ "no ip pim ssm prefix-list WORD",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Source Specific Multicast\n"
+ "group range prefix-list filter\n"
+ "Name of a prefix-list\n")
+{
+ struct pim_ssm *ssm = pimg->ssm_info;
+
+ if (ssm->plist_name && !strcmp(ssm->plist_name, argv[0]->arg))
+ return pim_ssm_cmd_worker (vty, NULL);
+
+ vty_out (vty, "%% pim ssm prefix-list %s doesn't exist%s",
+ argv[0]->arg, VTY_NEWLINE);
+
+ return CMD_WARNING;
+}
+
+static void
+ip_pim_ssm_show_group_range(struct vty *vty, u_char uj)
+{
+ struct pim_ssm *ssm = pimg->ssm_info;
+ const char *range_str = ssm->plist_name?ssm->plist_name:PIM_SSM_STANDARD_RANGE;
+
+ if (uj)
+ {
+ json_object *json;
+ json = json_object_new_object();
+ json_object_string_add(json, "ssmGroups", range_str);
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
+ }
+ else
+ vty_out(vty, "SSM group range : %s%s", range_str, VTY_NEWLINE);
+}
+
+DEFUN (show_ip_pim_ssm_range,
+ show_ip_pim_ssm_range_cmd,
+ "show ip pim group-type [json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ "PIM group type\n"
+ "JavaScript Object Notation\n")
+{
+ u_char uj = use_json(argc, argv);
+ ip_pim_ssm_show_group_range(vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+static void
+ip_pim_ssm_show_group_type(struct vty *vty, u_char uj, const char *group)
+{
+ struct in_addr group_addr;
+ const char *type_str;
+ int result;
+
+ result = inet_pton(AF_INET, group, &group_addr);
+ if (result <= 0)
+ type_str = "invalid";
+ else
+ {
+ if (pim_is_group_224_4 (group_addr))
+ type_str = pim_is_grp_ssm (group_addr)?"SSM":"ASM";
+ else
+ type_str = "not-multicast";
+ }
+
+ if (uj)
+ {
+ json_object *json;
+ json = json_object_new_object();
+ json_object_string_add(json, "groupType", type_str);
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
+ }
+ else
+ vty_out(vty, "Group type : %s%s", type_str, VTY_NEWLINE);
+}
+
+DEFUN (show_ip_pim_group_type,
+ show_ip_pim_group_type_cmd,
+ "show ip pim group-type A.B.C.D [json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ "multicast group type\n"
+ "group address\n"
+ "JavaScript Object Notation\n")
+{
+ u_char uj = use_json(argc, argv);
+ ip_pim_ssm_show_group_type(vty, uj, argv[0]->arg);
+
+ return CMD_SUCCESS;
+}
+
DEFUN_HIDDEN (ip_multicast_routing,
ip_multicast_routing_cmd,
"ip multicast-routing",
}
static int
-pim_cmd_interface_add (struct interface *ifp, enum pim_interface_type itype)
+pim_cmd_interface_add (struct interface *ifp)
{
struct pim_interface *pim_ifp = ifp->info;
PIM_IF_DO_PIM(pim_ifp->options);
}
- pim_ifp->itype = itype;
pim_if_addr_add_all(ifp);
pim_if_membership_refresh(ifp);
return 1;
}
-
-DEFUN (interface_ip_pim_ssm,
+DEFUN_HIDDEN (interface_ip_pim_ssm,
interface_ip_pim_ssm_cmd,
"ip pim ssm",
IP_STR
{
VTY_DECLVAR_CONTEXT(interface, ifp);
- if (!pim_cmd_interface_add(ifp, PIM_INTERFACE_SSM)) {
- vty_out(vty, "Could not enable PIM SSM on interface%s", VTY_NEWLINE);
+ if (!pim_cmd_interface_add(ifp)) {
+ vty_out(vty, "Could not enable PIM SM on interface%s", VTY_NEWLINE);
return CMD_WARNING;
}
+ vty_out(vty, "WARN: Enabled PIM SM on interface; configure PIM SSM range if needed%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
IFACE_PIM_SM_STR)
{
VTY_DECLVAR_CONTEXT(interface, ifp);
- if (!pim_cmd_interface_add(ifp, PIM_INTERFACE_SM)) {
+ if (!pim_cmd_interface_add(ifp)) {
vty_out(vty, "Could not enable PIM SM on interface%s", VTY_NEWLINE);
return CMD_WARNING;
}
return 1;
}
-DEFUN (interface_no_ip_pim_ssm,
+DEFUN_HIDDEN (interface_no_ip_pim_ssm,
interface_no_ip_pim_ssm_cmd,
"no ip pim ssm",
NO_STR
install_element (CONFIG_NODE, &no_ip_pim_rp_cmd);
install_element (CONFIG_NODE, &ip_pim_rp_prefix_list_cmd);
install_element (CONFIG_NODE, &no_ip_pim_rp_prefix_list_cmd);
+ install_element (CONFIG_NODE, &no_ip_pim_ssm_prefix_list_cmd);
+ install_element (CONFIG_NODE, &no_ip_pim_ssm_prefix_list_name_cmd);
+ install_element (CONFIG_NODE, &ip_pim_ssm_prefix_list_cmd);
install_element (CONFIG_NODE, &ip_pim_register_suppress_cmd);
install_element (CONFIG_NODE, &no_ip_pim_register_suppress_cmd);
install_element (CONFIG_NODE, &ip_pim_joinprune_time_cmd);
install_element (VIEW_NODE, &show_ip_msdp_sa_detail_cmd);
install_element (VIEW_NODE, &show_ip_msdp_sa_sg_cmd);
install_element (VIEW_NODE, &show_ip_msdp_mesh_group_cmd);
+ install_element (VIEW_NODE, &show_ip_pim_ssm_range_cmd);
+ install_element (VIEW_NODE, &show_ip_pim_group_type_cmd);
install_element (INTERFACE_NODE, &interface_pim_use_source_cmd);
install_element (INTERFACE_NODE, &interface_no_pim_use_source_cmd);
}
struct list *us;
};
-enum pim_interface_type {
- PIM_INTERFACE_SSM,
- PIM_INTERFACE_SM
-};
-
enum pim_secondary_addr_flags {
PIM_SEC_ADDRF_NONE = 0,
PIM_SEC_ADDRF_STALE = (1 << 0)
};
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 */
#include "pim_macro.h"
#include "pim_oil.h"
#include "pim_upstream.h"
+#include "pim_ssm.h"
int
pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2)
if (!PIM_IF_TEST_PIM(pim_ifp->options))
return 0;
+ /* skip (*,G) ch creation if G is of type SSM */
+ if (sg->src.s_addr == INADDR_ANY)
+ {
+ if (pim_is_grp_ssm (sg->grp))
+ {
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_debug("%s: local membership (S,G)=%s ignored as group is SSM",
+ __PRETTY_FUNCTION__, pim_str_sg_dump (sg));
+ return 1;
+ }
+ }
+
ch = pim_ifchannel_add(ifp, sg, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP);
if (!ch) {
return 0;
#include "pim_zebra.h"
#include "pim_msdp.h"
#include "pim_iface.h"
-#include "pim_rp.h"
extern struct host host;
pim_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);
+ prefix_list_add_hook (pim_prefix_list_update);
+ prefix_list_delete_hook (pim_prefix_list_update);
pim_route_map_init ();
pim_init();
DEFINE_MTYPE(PIMD, PIM_JP_AGG_SOURCE, "PIM JP AGG Source")
DEFINE_MTYPE(PIMD, PIM_PIM_INSTANCE, "PIM global state")
DEFINE_MTYPE(PIMD, PIM_NEXTHOP_CACHE, "PIM nexthop cache state")
+DEFINE_MTYPE(PIMD, PIM_SSM_INFO, "PIM SSM configuration")
DECLARE_MTYPE(PIM_JP_AGG_SOURCE)
DECLARE_MTYPE(PIM_PIM_INSTANCE)
DECLARE_MTYPE(PIM_NEXTHOP_CACHE)
+DECLARE_MTYPE(PIM_SSM_INFO)
#endif /* _QUAGGA_PIM_MEMORY_H */
#include "pim_register.h"
#include "pim_ifchannel.h"
#include "pim_zlookup.h"
+#include "pim_ssm.h"
/* GLOBAL VARS */
static struct thread *qpim_mroute_socket_reader = NULL;
*/
if ((pim_rpf_addr_is_inaddr_none (rpg)) ||
(!pim_ifp) ||
- (!(PIM_I_am_DR(pim_ifp))) ||
- (pim_ifp->itype == PIM_INTERFACE_SSM))
+ (!(PIM_I_am_DR(pim_ifp))))
{
if (PIM_DEBUG_MROUTE_DETAIL)
zlog_debug ("%s: Interface is not configured correctly to handle incoming packet: Could be !DR, !pim_ifp, !SM, !RP",
up->channel_oil->cc.pktcnt++;
PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
- pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
- up->reg_state = PIM_REG_JOIN;
+ pim_register_join (up);
return 0;
}
if ((pim_rpf_addr_is_inaddr_none (rpg)) ||
(!pim_ifp) ||
- (!(PIM_I_am_DR(pim_ifp))) ||
- (pim_ifp->itype == PIM_INTERFACE_SSM)) {
+ (!(PIM_I_am_DR(pim_ifp)))) {
if (PIM_DEBUG_MROUTE) {
zlog_debug("%s: Failed Check send packet", __PRETTY_FUNCTION__);
}
* 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) - sizeof (struct ip),
- pim_ifp->primary_address, rpg, 0, up);
+ {
+ if (pim_is_grp_ssm (sg.grp))
+ {
+ if (PIM_DEBUG_PIM_REG)
+ zlog_debug ("%s register forward skipped as group is SSM",
+ pim_str_sg_dump (&sg));
+ return 0;
+ }
+ pim_register_send((uint8_t *)buf + sizeof(struct ip),
+ ntohs (ip_hdr->ip_len) - sizeof (struct ip),
+ pim_ifp->primary_address, rpg, 0, up);
+ }
return 0;
}
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->reg_state = PIM_REG_JOIN;
+ pim_register_join (up);
pim_upstream_inherited_olist (up);
// Send the packet to the RP
#include "pim_zebra.h"
#include "pim_join.h"
#include "pim_util.h"
+#include "pim_ssm.h"
struct thread *send_test_packet_timer = NULL;
+void
+pim_register_join (struct pim_upstream *up)
+{
+ if (pim_is_grp_ssm (up->sg.grp))
+ {
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_debug ("%s register setup skipped as group is SSM", up->sg_str);
+ return;
+ }
+
+ pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
+ up->reg_state = PIM_REG_JOIN;
+}
+
void
pim_register_stop_send (struct interface *ifp, struct prefix_sg *sg,
struct in_addr src, struct in_addr originator)
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);
+void pim_register_join (struct pim_upstream *up);
#endif
--- /dev/null
+/*
+ * IP SSM ranges for FRR
+ * Copyright (C) 2017 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/linklist.h>
+#include <lib/prefix.h>
+#include <lib/vty.h>
+#include <lib/vrf.h>
+#include <lib/plist.h>
+
+#include "pimd.h"
+#include "pim_ssm.h"
+#include "pim_zebra.h"
+
+static void
+pim_ssm_range_reevaluate (void)
+{
+ /* 1. Setup register state for (S,G) entries if G has changed from SSM to
+ * ASM.
+ * 2. check existing (*,G) IGMP registrations to see if they are
+ * still ASM. if they are now SSM delete them.
+ * 3. Allow channel setup for IGMP (*,G) members if G is now ASM
+ * 4. I could tear down all (*,G), (S,G,rpt) states. But that is an
+ * unnecessary sladge hammer and may not be particularly useful as it is
+ * likely the SPT switchover has already happened for flows along such RPTs.
+ * As for the RPT states it seems that the best thing to do is let them age
+ * out gracefully. As long as the FHR and LHR do the right thing RPTs will
+ * disappear in time for SSM groups.
+ */
+ pim_upstream_register_reevaluate ();
+ igmp_source_forward_reevaluate_all ();
+}
+
+void
+pim_ssm_prefix_list_update (struct prefix_list *plist)
+{
+ struct pim_ssm *ssm = pimg->ssm_info;
+
+ if (!ssm->plist_name || strcmp (ssm->plist_name, prefix_list_name (plist)))
+ {
+ /* not ours */
+ return;
+ }
+
+ pim_ssm_range_reevaluate ();
+}
+
+static int
+pim_is_grp_standard_ssm (struct prefix *group)
+{
+ static int first = 1;
+ static struct prefix group_ssm;
+
+ if (first)
+ {
+ str2prefix (PIM_SSM_STANDARD_RANGE, &group_ssm);
+ first = 0;
+ }
+
+ return prefix_match (&group_ssm, group);
+}
+
+int
+pim_is_grp_ssm (struct in_addr group_addr)
+{
+ struct pim_ssm *ssm;
+ struct prefix group;
+ struct prefix_list *plist;
+
+ memset (&group, 0, sizeof (group));
+ group.family = AF_INET;
+ group.u.prefix4 = group_addr;
+ group.prefixlen = 32;
+
+ ssm = pimg->ssm_info;
+ if (!ssm->plist_name)
+ {
+ return pim_is_grp_standard_ssm (&group);
+ }
+
+ plist = prefix_list_lookup (AFI_IP, ssm->plist_name);
+ if (!plist)
+ return 0;
+
+ return (prefix_list_apply (plist, &group) == PREFIX_PERMIT);
+}
+
+int
+pim_ssm_range_set (vrf_id_t vrf_id, const char *plist_name)
+{
+ struct pim_ssm *ssm;
+ int change = 0;
+
+ if (vrf_id != VRF_DEFAULT)
+ return PIM_SSM_ERR_NO_VRF;
+
+ ssm = pimg->ssm_info;
+ if (plist_name)
+ {
+ if (ssm->plist_name)
+ {
+ if (!strcmp (ssm->plist_name, plist_name))
+ return PIM_SSM_ERR_DUP;
+ XFREE (MTYPE_PIM_FILTER_NAME, ssm->plist_name);
+ }
+ ssm->plist_name = XSTRDUP (MTYPE_PIM_FILTER_NAME, plist_name);
+ change = 1;
+ }
+ else
+ {
+ if (ssm->plist_name)
+ {
+ change = 1;
+ XFREE (MTYPE_PIM_FILTER_NAME, ssm->plist_name);
+ }
+ }
+
+ if (change)
+ pim_ssm_range_reevaluate ();
+
+ return PIM_SSM_ERR_NONE;
+}
+
+void *
+pim_ssm_init (vrf_id_t vrf_id)
+{
+ struct pim_ssm *ssm;
+
+ ssm = XCALLOC (MTYPE_PIM_SSM_INFO, sizeof (*ssm));
+ ssm->vrf_id = vrf_id;
+
+ return ssm;
+}
+
+void
+pim_ssm_terminate (struct pim_ssm *ssm)
+{
+ if (ssm && ssm->plist_name)
+ XFREE (MTYPE_PIM_FILTER_NAME, ssm->plist_name);
+}
--- /dev/null
+/*
+ * IP SSM ranges for FRR
+ * Copyright (C) 2017 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_SSM_H
+#define PIM_SSM_H
+
+#define PIM_SSM_STANDARD_RANGE "232.0.0.0/8"
+
+/* SSM error codes */
+enum pim_ssm_err
+{
+ PIM_SSM_ERR_NONE = 0,
+ PIM_SSM_ERR_NO_VRF = -1,
+ PIM_SSM_ERR_DUP = -2,
+};
+
+struct pim_ssm
+{
+ vrf_id_t vrf_id;
+ char *plist_name; /* prefix list of group ranges */
+};
+
+void pim_ssm_prefix_list_update (struct prefix_list *plist);
+int pim_is_grp_ssm (struct in_addr group_addr);
+int pim_ssm_range_set (vrf_id_t vrf_id, const char *plist_name);
+void *pim_ssm_init (vrf_id_t vrf_id);
+void pim_ssm_terminate (struct pim_ssm *ssm);
+#endif
#include "pim_msdp.h"
#include "pim_jp_agg.h"
#include "pim_nht.h"
+#include "pim_ssm.h"
struct hash *pim_upstream_hash = NULL;
struct list *pim_upstream_list = NULL;
return 0;
}
+/* Source registration is supressed for SSM groups. When the SSM range changes
+ * we re-revaluate register setup for existing upstream entries */
+void
+pim_upstream_register_reevaluate (void)
+{
+ struct listnode *upnode;
+ struct pim_upstream *up;
+
+ for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, upnode, up))
+ {
+ /* If FHR is set CouldRegister is True. Also check if the flow
+ * is actually active; if it is not kat setup will trigger source
+ * registration whenever the flow becomes active. */
+ if (!PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) || !up->t_ka_timer)
+ continue;
+
+ if (pim_is_grp_ssm (up->sg.grp))
+ {
+ /* clear the register state for SSM groups */
+ if (up->reg_state != PIM_REG_NOINFO)
+ {
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_debug ("Clear register for %s as G is now SSM",
+ up->sg_str);
+ /* remove regiface from the OIL if it is there*/
+ pim_channel_del_oif (up->channel_oil, pim_regiface,
+ PIM_OIF_FLAG_PROTO_PIM);
+ up->reg_state = PIM_REG_NOINFO;
+ }
+ }
+ else
+ {
+ /* register ASM sources with the RP */
+ if (up->reg_state == PIM_REG_NOINFO)
+ {
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_debug ("Register %s as G is now ASM", up->sg_str);
+ pim_channel_add_oif (up->channel_oil, pim_regiface,
+ PIM_OIF_FLAG_PROTO_PIM);
+ up->reg_state = PIM_REG_JOIN;
+ }
+ }
+ }
+}
+
void
pim_upstream_switch(struct pim_upstream *up,
enum pim_upstream_state new_state)
PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
if (!old_fhr && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
{
- up->reg_state = PIM_REG_JOIN;
pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
- pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
+ pim_register_join (up);
}
}
else
zlog_debug ("kat started on %s; set fhr reg state to joined", up->sg_str);
PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
- if (up->reg_state == PIM_REG_NOINFO) {
- pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
- up->reg_state = PIM_REG_JOIN;
- }
+ if (up->reg_state == PIM_REG_NOINFO)
+ pim_register_join (up);
}
}
void join_timer_start (struct pim_upstream *up);
int pim_upstream_compare (void *arg1, void *arg2);
+void pim_upstream_register_reevaluate (void);
#endif /* PIM_UPSTREAM_H */
#include "pim_static.h"
#include "pim_rp.h"
#include "pim_msdp.h"
+#include "pim_ssm.h"
int
pim_debug_config_write (struct vty *vty)
int pim_global_config_write(struct vty *vty)
{
int writes = 0;
+ struct pim_ssm *ssm = pimg->ssm_info;
writes += pim_msdp_config_write (vty);
qpim_packet_process, VTY_NEWLINE);
++writes;
}
+ if (ssm->plist_name)
+ {
+ vty_out (vty, "ip pim ssm prefix-list %s%s",
+ ssm->plist_name, VTY_NEWLINE);
+ ++writes;
+ }
if (qpim_ssmpingd_list) {
struct listnode *node;
if (ifp->info) {
struct pim_interface *pim_ifp = ifp->info;
- /* IF ip pim ssm */
if (PIM_IF_TEST_PIM(pim_ifp->options)) {
- if (pim_ifp->itype == PIM_INTERFACE_SSM)
- vty_out(vty, " ip pim ssm%s", VTY_NEWLINE);
- else
- vty_out(vty, " ip pim sm%s", VTY_NEWLINE);
+ vty_out(vty, " ip pim sm%s", VTY_NEWLINE);
++writes;
}
#include "pim_igmpv3.h"
#include "pim_jp_agg.h"
#include "pim_nht.h"
+#include "pim_ssm.h"
#undef PIM_DEBUG_IFADDR_DUMP
#define PIM_DEBUG_IFADDR_DUMP
return vif_index;
}
+static void
+igmp_source_forward_reevaluate_one(struct igmp_source *source)
+{
+ struct prefix_sg sg;
+ struct igmp_group *group = source->source_group;
+ struct pim_ifchannel *ch;
+
+ if ((source->source_addr.s_addr != INADDR_ANY) ||
+ !IGMP_SOURCE_TEST_FORWARDING (source->source_flags))
+ return;
+
+ memset (&sg, 0, sizeof (struct prefix_sg));
+ sg.src = source->source_addr;
+ sg.grp = group->group_addr;
+
+ ch = pim_ifchannel_find (group->group_igmp_sock->interface, &sg);
+ if (pim_is_grp_ssm (group->group_addr))
+ {
+ /* If SSM group withdraw local membership */
+ if (ch && (ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE))
+ {
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_debug ("local membership del for %s as G is now SSM",
+ pim_str_sg_dump (&sg));
+ pim_ifchannel_local_membership_del (group->group_igmp_sock->interface, &sg);
+ }
+ }
+ else
+ {
+ /* If ASM group add local membership */
+ if (!ch || (ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO))
+ {
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_debug ("local membership add for %s as G is now ASM",
+ pim_str_sg_dump (&sg));
+ pim_ifchannel_local_membership_add (group->group_igmp_sock->interface, &sg);
+ }
+ }
+}
+
+void
+igmp_source_forward_reevaluate_all(void)
+{
+ struct listnode *ifnode;
+ struct interface *ifp;
+
+ for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp))
+ {
+ struct pim_interface *pim_ifp = ifp->info;
+ struct listnode *sock_node;
+ struct igmp_sock *igmp;
+
+ if (!pim_ifp)
+ continue;
+
+ /* scan igmp sockets */
+ for (ALL_LIST_ELEMENTS_RO (pim_ifp->igmp_socket_list, sock_node, igmp))
+ {
+ struct listnode *grpnode;
+ struct igmp_group *grp;
+
+ /* scan igmp groups */
+ for (ALL_LIST_ELEMENTS_RO (igmp->igmp_group_list, grpnode, grp))
+ {
+ struct listnode *srcnode;
+ struct igmp_source *src;
+
+ /* scan group sources */
+ for (ALL_LIST_ELEMENTS_RO (grp->group_source_list,
+ srcnode, src))
+ {
+ igmp_source_forward_reevaluate_one (src);
+ } /* scan group sources */
+ } /* scan igmp groups */
+ } /* scan igmp sockets */
+ } /* scan interfaces */
+}
+
void igmp_source_forward_start(struct igmp_source *source)
{
struct igmp_group *group;
void igmp_source_forward_start(struct igmp_source *source);
void igmp_source_forward_stop(struct igmp_source *source);
+void igmp_source_forward_reevaluate_all(void);
void pim_forward_start(struct pim_ifchannel *ch);
void pim_forward_stop(struct pim_ifchannel *ch);
#include "pim_ssmpingd.h"
#include "pim_static.h"
#include "pim_rp.h"
+#include "pim_ssm.h"
#include "pim_zlookup.h"
#include "pim_nht.h"
list_delete_all_node (pnc->upstream_list);
}
+void
+pim_prefix_list_update (struct prefix_list *plist)
+{
+ pim_rp_prefix_list_update (plist);
+ pim_ssm_prefix_list_update (plist);
+}
+
static void
pim_instance_terminate (void)
{
hash_clean (pimg->rpf_hash, (void *) pim_rp_list_hash_clean);
hash_free (pimg->rpf_hash);
}
+ pim_ssm_terminate (pimg->ssm_info);
XFREE (MTYPE_PIM_PIM_INSTANCE, pimg);
}
if (PIM_DEBUG_ZEBRA)
zlog_debug ("%s: NHT rpf hash init ", __PRETTY_FUNCTION__);
+ pim->ssm_info = pim_ssm_init (vrf_id);
+ if (!pim->ssm_info) {
+ pim_instance_terminate ();
+ return NULL;
+ }
return pim;
}
#include <stdint.h>
#include "zebra.h"
#include "libfrr.h"
+#include "prefix.h"
+#include "vty.h"
+#include "plist.h"
#include "pim_str.h"
#include "pim_memory.h"
vrf_id_t vrf_id;
struct hash *rpf_hash;
+ void *ssm_info; /* per-vrf SSM configuration */
+
int send_v6_secondary;
};
extern void pim_route_map_init (void);
extern void pim_route_map_terminate(void);
void pim_vrf_init (void);
+void pim_prefix_list_update (struct prefix_list *plist);
#endif /* PIMD_H */