-Free Range Routing is free software that manages various IPv4 and IPv6 routing
+FRRouting is free software that manages various IPv4 and IPv6 routing
protocols.
-Currently Free Range Routing supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1,
+Currently FRRouting supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1,
RIPv2, RIPng, PIM-SM/MSDP and LDP as well as very early support for IS-IS.
See the file REPORTING-BUGS to report bugs.
-Free Range Routing is free software. See the file COPYING for copying conditions.
+Free RRRouting is free software. See the file COPYING for copying conditions.
-Public email discussion can be found at https://lists.nox.tf/listinfo/frr
+Public email discussion can be found at https://lists.frrouting.org/listinfo
-Our public slack channel is at https://freerangerouting.slack.com
+Our public slack channel is at https://frrouting.slack.com
/* Ethernet-VPN Attribute handling file
Copyright (C) 2016 6WIND
-This file is part of Free Range Routing.
+This file is part of FRRouting.
-Free Range Routing is free software; you can redistribute it and/or modify it
+FRRouting 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.
-Free Range Routing is distributed in the hope that it will be useful, but
+FRRouting 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 Free Range Routing; see the file COPYING. If not, write to the Free
+along with FRRouting; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
/* E-VPN attribute handling structure file
Copyright (C) 2016 6WIND
-This file is part of Free Range Routing.
+This file is part of FRRouting.
-Free Range Routing is free software; you can redistribute it and/or modify it
+FRRouting 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.
-Free Range Routing is distributed in the hope that it will be useful, but
+FRRouting 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 Free Range Routing; see the file COPYING. If not, write to the Free
+along with FRRouting; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
/* Ethernet-VPN Packet and vty Processing File
Copyright (C) 2016 6WIND
-This file is part of Free Range Routing.
+This file is part of FRRouting.
-Free Range Routing is free software; you can redistribute it and/or modify it
+FRRouting 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.
-Free Range Routing is distributed in the hope that it will be useful, but
+FRRouting 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 Free Range Routing; see the file COPYING. If not, write to the Free
+along with FRRouting; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
/* E-VPN header for packet handling
Copyright (C) 2016 6WIND
-This file is part of Free Range Routing.
+This file is part of FRRouting.
-Free Range Routing is free software; you can redistribute it and/or modify it
+FRRouting 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.
-Free Range Routing is distributed in the hope that it will be useful, but
+FRRouting 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 Free Range Routing; see the file COPYING. If not, write to the Free
+along with FRRouting; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
/* Ethernet-VPN Packet and vty Processing File
Copyright (C) 2017 6WIND
-This file is part of Free Range Routing
+This file is part of FRRouting
-Free Range Routing is free software; you can redistribute it and/or modify it
+FRRouting 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.
-Free Range Routing is distributed in the hope that it will be useful, but
+FRRouting 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 Free Range Routing; see the file COPYING. If not, write to the Free
+along with FRRouting; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
/* EVPN VTY functions to EVPN
Copyright (C) 2017 6WIND
-This file is part of Free Range Routing.
+This file is part of FRRouting.
-Free Range Routing is free software; you can redistribute it and/or modify it
+FRRouting 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.
-Free Range Routing is distributed in the hope that it will be useful, but
+FRRouting 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 Free Range Routing; see the file COPYING. If not, write to the Free
+along with FRRouting; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
{ "listenon", required_argument, NULL, 'l'},
{ "retain", no_argument, NULL, 'r'},
{ "no_kernel", no_argument, NULL, 'n'},
+ { "skip_runas", no_argument, NULL, 'S'},
{ "ecmp", required_argument, NULL, 'e'},
{ 0 }
};
if (! retain_mode)
{
bgp_terminate ();
- zprivs_terminate (&bgpd_privs);
+ if (bgpd_privs.user) /* NULL if skip_runas flag set */
+ zprivs_terminate (&bgpd_privs);
}
bgp_exit (0);
int bgp_port = BGP_PORT_DEFAULT;
char *bgp_address = NULL;
+ int no_fib_flag = 0;
+ int skip_runas = 0;
frr_preinit(&bgpd_di, argc, argv);
frr_opt_add("p:l:rne:", longopts,
" -l, --listenon Listen on specified address (implies -n)\n"
" -r, --retain When program terminates, retain added route by bgpd.\n"
" -n, --no_kernel Do not install route to kernel.\n"
+ " -S, --skip_runas Skip capabilities checks, and changing user and group IDs.\n"
" -e, --ecmp Specify ECMP to use.\n");
/* Command line argument treatment. */
if (tmp_port <= 0 || tmp_port > 0xffff)
bgp_port = BGP_PORT_DEFAULT;
else
- bm->port = tmp_port;
+ bgp_port = tmp_port;
break;
case 'e':
multipath_num = atoi (optarg);
bgp_address = optarg;
/* listenon implies -n */
case 'n':
- bgp_option_set (BGP_OPT_NO_FIB);
+ no_fib_flag = 1;
+ break;
+ case 'S':
+ skip_runas = 1;
break;
default:
frr_help_exit (1);
break;
}
}
+ if (skip_runas)
+ memset (&bgpd_privs, 0, sizeof (bgpd_privs));
/* BGP master init. */
bgp_master_init (frr_init ());
bm->port = bgp_port;
bm->address = bgp_address;
+ if (no_fib_flag)
+ bgp_option_set (BGP_OPT_NO_FIB);
/* Initializations. */
bgp_vrf_init ();
buffer_putc (b, ' ');
else
{
- if (strmatch (argv[i]->text, "<AA:BB:CC>"))
+ if (strmatch (argv[i]->text, "AA:BB:CC"))
{
first = 1;
buffer_putstr (b, argv[i]->arg);
XFREE (MTYPE_TMP, str);
if (! lcom)
{
- vty_out (vty, "%% Large-community malformed: %s", VTY_NEWLINE);
+ vty_out (vty, "%% Large-community malformed%s", VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_WARNING;
}
- argv_find (argv, argc, "large-community", &idx);
- if (strmatch(argv[idx+1]->text, "AA:BB:CC"))
+ if (argv_find (argv, argc, "AA:BB:CC", &idx))
return bgp_show_lcommunity (vty, bgp, argc, argv, afi, safi, uj);
else
return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_all, NULL, uj);
bgp_show_regexp (struct vty *vty, const char *regstr, afi_t afi,
safi_t safi, enum bgp_show_type type)
{
- return CMD_SUCCESS;
-
regex_t *regex;
int rc;
{
unsigned int num;
- if (sscanf(arg, "last-as %u", &num) == 1 && num > 0 && num < 10)
+ if (sscanf(arg, "last-as %u", &num) == 1 && num > 0 && num <= 10)
return (void*)(uintptr_t)num;
return route_aspath_compile(arg);
DEFUN (set_aspath_prepend_lastas,
set_aspath_prepend_lastas_cmd,
- "set as-path prepend last-as (1-9)",
+ "set as-path prepend last-as (1-10)",
SET_STR
"Transform BGP AS_PATH attribute\n"
"Prepend to the as-path\n"
"Use the peer's AS-number\n"
- "Number of times to insert")
+ "Number of times to insert\n")
{
return set_aspath_prepend_asn (self, vty, argc, argv);
}
/* VPN Related functions
Copyright (C) 2017 6WIND
-This file is part of Free Range Routing
+This file is part of FRRouting
-Free Range Routing is free software; you can redistribute it and/or modify it
+FRRouting 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.
-Free Range Routing is distributed in the hope that it will be useful, but
+FRRouting 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 Free Range Routing; see the file COPYING. If not, write to the Free
+along with FRRouting; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
/* VPN common functions to MP-BGP
Copyright (C) 2017 6WIND
-This file is part of Free Range Routing.
+This file is part of FRRouting.
-Free Range Routing is free software; you can redistribute it and/or modify it
+FRRouting 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.
-Free Range Routing is distributed in the hope that it will be useful, but
+FRRouting 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 Free Range Routing; see the file COPYING. If not, write to the Free
+along with FRRouting; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
##
AC_PREREQ(2.60)
-AC_INIT(frr, 2.1-dev, [https://github.com/frrouting/frr/issues])
+AC_INIT(frr, 3.1-dev, [https://github.com/frrouting/frr/issues])
PACKAGE_URL="https://frrouting.org/"
PACKAGE_FULLNAME="FRRouting"
AC_SUBST(PACKAGE_FULLNAME)
+frr (3.1-dev) Released; urgency=medium
+
+ * New Enabled: PIM draft Unnumbered
+
+ -- frr <frog@lists.frrouting.org> Wed, 5 Apr 2017 22:29:42 -0500
+
+frr (3.0) Released; urgency=medium
+
+ * New Enabled: BGP Shutdown Message
+ * New Enabled: BGP Large Community
+ * New Enabled: BGP RFC 7432 Partial Support w/ Ethernet VPN
+ * New Enabled: BGP EVPN RT-5
+ * New Enabled: LDP RFC 5561
+ * New Enabled: LDP RFC 5918
+ * New Enabled: LDP RFC 5919
+ * New Enabled: LDP RFC 6667
+ * New Enabled: LDP RFC 7473
+ * New Enabled: OSPF RFC 4552
+ * New Enabled: ISIS SPF Backoff draft
+ * New Enabled: PIM Unnumbered Interfaces
+ * New Enabled: PIM RFC 4611
+ * New Enabled: PIM Sparse Mode
+ * New Enabled: NHRP RFC 2332
+ * New Enabled: Label Manager
+
+ -- frr <frr@lists.nox.tf> Wed, 5 Apr 2017 22:23:42 -0500
+
frr (2.1) Released; urgency=medium
* Switchover to FRR
sudo addgroup --system --gid 92 frr
sudo addgroup --system --gid 85 frrvty
- sudo adduser --system --ingroup frr --groups frrvty --home /var/run/frr/ \
- --gecos "FRR FRRouting suite" --shell /bin/false frr
- sudo usermode
+ sudo adduser --system --ingroup frr --home /var/run/frr/ \
+ --gecos "FRR suite" --shell /bin/false frr
+ sudo usermod -a -G frrvty frr
### Download Source, configure and compile it
(You may prefer different options on configure statement. These are just
--enable-rtadv \
--enable-tcp-zebra \
--enable-fpm \
+ --enable-ldpd \
--with-pkg-git-version \
--with-pkg-extra-version=-MyOwnFRRVersion
make
sudo make install
### Create empty FRR configuration files
+
sudo install -m 755 -o frr -g frr -d /var/log/frr
sudo install -m 775 -o frr -g frrvty -d /etc/frr
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
### Enable IP & IPv6 forwarding
# based on Router Advertisements for this host
net.ipv6.conf.all.forwarding=1
-**Reboot** or use `sysctl` to apply the same config to the running system
+**Reboot** or use `sysctl -p` to apply the same config to the running system
sudo touch /etc/frr/ripngd.conf
sudo touch /etc/frr/pimd.conf
sudo touch /etc/frr/ldpd.conf
+ sudo touch /etc/frr/nhrpd.conf
sudo chown -R frr:frr /etc/frr/
sudo touch /etc/frr/vtysh.conf
sudo chown frr:frrvt /etc/frr/vtysh.conf
install -p -m 644 redhat/ospf6d.service /usr/lib/systemd/system/ospf6d.service
install -p -m 644 redhat/ripngd.service /usr/lib/systemd/system/ripngd.service
install -p -m 644 redhat/pimd.service /usr/lib/systemd/system/pimd.service
- install -p -m 644 redhat/pimd.service /usr/lib/systemd/system/ldpd.service
+ install -p -m 644 redhat/ldpd.service /usr/lib/systemd/system/ldpd.service
install -p -m 644 redhat/frr.sysconfig /etc/sysconfig/frr
install -p -m 644 redhat/frr.logrotate /etc/logrotate.d/frr
sudo touch /etc/frr/ripngd.conf
sudo touch /etc/frr/pimd.conf
sudo touch /etc/frr/ldpd.conf
+ sudo touch /etc/frr/nhrpd.conf
sudo chown -R _frr:_frr /etc/frr
sudo touch /etc/frr/vtysh.conf
sudo chown -R _frr:_frrvty /etc/frr/vtysh.conf
sudo groupadd -g 92 frr
sudo groupadd -r -g 85 frrvty
- sudo adduser --system --ingroup frr --groups frrvty --home /var/run/frr/ \
+ sudo adduser --system --ingroup frr --home /var/run/frr/ \
--gecos "FRR suite" --shell /sbin/nologin frr
+ sudo usermod -a -G frrvty frr
### Download Source, configure and compile it
(You may prefer different options on configure statement. These are just
### Create empty FRR configuration files
- sudo mkdir /var/log/frr
- sudo chown frr:frr /var/log/frr
- sudo mkdir /etc/frr
- sudo touch /etc/frr/zebra.conf
- sudo touch /etc/frr/bgpd.conf
- sudo touch /etc/frr/ospfd.conf
- sudo touch /etc/frr/ospf6d.conf
- sudo touch /etc/frr/isisd.conf
- sudo touch /etc/frr/ripd.conf
- sudo touch /etc/frr/ripngd.conf
- sudo touch /etc/frr/pimd.conf
- sudo touch /etc/frr/ldpd.conf
- sudo chown frr:frr /etc/frr/
- sudo touch /etc/frr/vtysh.conf
- sudo chown frr:frrvty /etc/frr/vtysh.conf
- sudo chmod 640 /etc/frr/*.conf
+ sudo install -m 755 -o frr -g frr -d /var/log/frr
+ sudo install -m 775 -o frr -g frrvty -d /etc/frr
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
+ sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
### Enable IP & IPv6 forwarding
# based on Router Advertisements for this host
net.ipv6.conf.all.forwarding=1
-**Reboot** or use `sysctl` to apply the same config to the running system
+**Reboot** or use `sysctl -p` to apply the same config to the running system
sudo groupadd -g 92 frr
sudo groupadd -r -g 85 frrvty
- sudo adduser --system --ingroup frr --groups frrvty --home /var/run/frr/ \
+ sudo adduser --system --ingroup frr --home /var/run/frr/ \
--gecos "FRR suite" --shell /sbin/nologin frr
+ sudo usermod -a -G frrvty frr
### Download Source, configure and compile it
(You may prefer different options on configure statement. These are just
--enable-rtadv \
--enable-tcp-zebra \
--enable-fpm \
+ --enable-ldpd \
--with-pkg-git-version \
--with-pkg-extra-version=-MyOwnFRRVersion
make
### Create empty FRR configuration files
- sudo mkdir /var/log/frr
- sudo chown frr:frr /var/log/frr
- sudo mkdir /etc/frr
- sudo touch /etc/frr/zebra.conf
- sudo touch /etc/frr/bgpd.conf
- sudo touch /etc/frr/ospfd.conf
- sudo touch /etc/frr/ospf6d.conf
- sudo touch /etc/frr/isisd.conf
- sudo touch /etc/frr/ripd.conf
- sudo touch /etc/frr/ripngd.conf
- sudo touch /etc/frr/pimd.conf
- sudo chown frr:frr /etc/frr/
- sudo touch /etc/frr/vtysh.conf
- sudo chown frr:frrvty /etc/frr/vtysh.conf
- sudo chmod 640 /etc/frr/*.conf
+ sudo install -m 755 -o frr -g frr -d /var/log/frr
+ sudo install -m 775 -o frr -g frrvty -d /etc/frr
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
+ sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
### Enable IP & IPv6 forwarding
# based on Router Advertisements for this host
net.ipv6.conf.all.forwarding=1
-**Reboot** or use `sysctl` to apply the same config to the running system
+**Reboot** or use `sysctl -p` to apply the same config to the running system
sudo groupadd -g 92 frr
sudo groupadd -r -g 85 frrvty
- sudo adduser --system --ingroup frr --groups frrvty --home /var/run/frr/ \
+ sudo adduser --system --ingroup frr --home /var/run/frr/ \
--gecos "FRR suite" --shell /sbin/nologin frr
+ sudo usermod -a -G frrvty frr
### Download Source, configure and compile it
(You may prefer different options on configure statement. These are just
### Create empty FRR configuration files
- sudo mkdir /var/log/frr
- sudo chown frr:frr /var/log/frr
- sudo mkdir /etc/frr
- sudo touch /etc/frr/zebra.conf
- sudo touch /etc/frr/bgpd.conf
- sudo touch /etc/frr/ospfd.conf
- sudo touch /etc/frr/ospf6d.conf
- sudo touch /etc/frr/isisd.conf
- sudo touch /etc/frr/ripd.conf
- sudo touch /etc/frr/ripngd.conf
- sudo touch /etc/frr/pimd.conf
- sudo touch /etc/frr/ldpd.conf
- sudo chown frr:frr /etc/frr/
- sudo touch /etc/frr/vtysh.conf
- sudo chown frr:frrvty /etc/frr/vtysh.conf
- sudo chmod 640 /etc/frr/*.conf
+ sudo install -m 755 -o frr -g frr -d /var/log/frr
+ sudo install -m 775 -o frr -g frrvty -d /etc/frr
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
+ sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
+ sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
### Enable IP & IPv6 forwarding
mpls-router
mpls-iptunnel
-**Reboot** or use `sysctl` to apply the same config to the running system
+**Reboot** or use `sysctl -p` to apply the same config to the running system
After configuring the software, you will need to compile it for your
system. Simply issue the command @command{make} in the root of the source
-directory and the software will be compiled. If you have *any* problems
-at this stage, be certain to send a bug report @xref{Bug Reports}.
+directory and the software will be compiled. Cliff Note versions of
+different compilation examples can be found in the doc/Building_FRR_on_XXX.md
+files. If you have *any* problems at this stage, be certain to send a
+bug report @xref{Bug Reports}.
@example
-% ./configure
-.
-.
-.
-./configure output
-.
-.
-.
+% ./bootstrap.sh
+% ./configure <appropriate to your system>
% make
@end example
@c A - End of node, Building the Software
*/
%{
+/* ignore harmless bug in old versions of flex */
+#pragma GCC diagnostic ignored "-Wsign-compare"
+
#include "command_parse.h"
#define YY_USER_ACTION yylloc->last_column += yyleng;
distribute_list_cmd,
"distribute-list [prefix] WORD <in|out> [WORD]",
"Filter networks in routing updates\n"
+ "Specify a prefix\n"
"Access-list name\n"
"Filter incoming routing updates\n"
"Filter outgoing routing updates\n"
no_distribute_list_cmd,
"no [ipv6] distribute-list [prefix] WORD <in|out> [WORD]",
NO_STR
+ "IPv6\n"
"Filter networks in routing updates\n"
+ "Specify a prefix\n"
"Access-list name\n"
"Filter incoming routing updates\n"
"Filter outgoing routing updates\n"
const char frr_sysconfdir[] = SYSCONFDIR;
const char frr_vtydir[] = DAEMON_VTY_DIR;
+const char frr_moduledir[] = MODULE_PATH;
char config_default[256];
static char pidfile_default[256];
}
-#define OPTION_VTYSOCK 1000
+#define OPTION_VTYSOCK 1000
+#define OPTION_MODULEDIR 1002
static const struct option lo_always[] = {
{ "help", no_argument, NULL, 'h' },
{ "daemon", no_argument, NULL, 'd' },
{ "module", no_argument, NULL, 'M' },
{ "vty_socket", required_argument, NULL, OPTION_VTYSOCK },
+ { "moduledir", required_argument, NULL, OPTION_MODULEDIR },
{ NULL }
};
static const struct optspec os_always = {
" -v, --version Print program version\n"
" -d, --daemon Runs in daemon mode\n"
" -M, --module Load specified module\n"
- " --vty_socket Override vty socket path\n",
+ " --vty_socket Override vty socket path\n"
+ " --moduledir Override modules directory\n",
lo_always
};
struct option_chain *next;
const char *arg;
};
+
static struct option_chain *modules = NULL, **modnext = &modules;
static int errors = 0;
}
di->vty_sock_path = optarg;
break;
+ case OPTION_MODULEDIR:
+ if (di->module_path) {
+ fprintf(stderr, "----moduledir option specified more than once!\n");
+ errors++;
+ break;
+ }
+ di->module_path = optarg;
+ break;
case 'u':
if (di->flags & FRR_NO_PRIVSEP)
return 1;
struct option_chain *oc;
struct frrmod_runtime *module;
char moderr[256];
+ const char *dir;
+ dir = di->module_path ? di->module_path : frr_moduledir;
srandom(time(NULL));
frrmod_init(di->module);
while (modules) {
modules = (oc = modules)->next;
- module = frrmod_load(oc->arg, moderr, sizeof(moderr));
+ module = frrmod_load(oc->arg, dir, moderr, sizeof(moderr));
if (!module) {
fprintf(stderr, "%s\n", moderr);
exit(1);
const char *config_file;
const char *pid_file;
const char *vty_path;
+ const char *module_path;
const char *proghelp;
void (*printhelp)(FILE *target);
extern char config_default[256];
extern const char frr_sysconfdir[];
extern const char frr_vtydir[];
+extern const char frr_moduledir[];
#endif /* _ZEBRA_FRR_H */
}
struct frrmod_runtime *frrmod_load(const char *spec,
- char *err, size_t err_len)
+ const char *dir, char *err, size_t err_len)
{
void *handle = NULL;
char name[PATH_MAX], fullpath[PATH_MAX], *args;
if (!strchr(name, '/')) {
if (!handle && execname) {
snprintf(fullpath, sizeof(fullpath), "%s/%s_%s.so",
- MODULE_PATH, execname, name);
+ dir, execname, name);
handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL);
}
if (!handle) {
snprintf(fullpath, sizeof(fullpath), "%s/%s.so",
- MODULE_PATH, name);
+ dir, name);
handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL);
}
}
extern void frrmod_init(struct frrmod_runtime *modinfo);
extern struct frrmod_runtime *frrmod_load(const char *spec,
- char *err, size_t err_len);
+ const char *dir, char *err, size_t err_len);
#if 0
/* not implemented yet */
extern void frrmod_unload(struct frrmod_runtime *module);
trickle_down (index, queue);
}
}
+
+void
+pqueue_remove (void *data, struct pqueue *queue)
+{
+ for (int i = 0; i < queue->size; i++)
+ if (queue->array[i] == data)
+ pqueue_remove_at (i, queue);
+}
extern void pqueue_enqueue (void *data, struct pqueue *queue);
extern void *pqueue_dequeue (struct pqueue *queue);
extern void pqueue_remove_at (int index, struct pqueue *queue);
+extern void pqueue_remove (void *data, struct pqueue *queue);
extern void trickle_down (int index, struct pqueue *queue);
extern void trickle_up (int index, struct pqueue *queue);
}
}
+ zprivs_state.zsuid = geteuid(); /* initial uid */
/* add groups only if we changed uid - otherwise skip */
if ((ngroups) && (zprivs_state.zsuid != zprivs_state.zuid))
{
vrf_id_t vrf_id;
u_int16_t cmd;
- zlog_debug ("Connecting to Label Manager");
+ if (zclient_debug)
+ zlog_debug ("Connecting to Label Manager");
+
if (zclient->sock < 0)
return -1;
zclient->sock = -1;
return -1;
}
- zlog_debug ("%s: Label manager connect request (%d bytes) sent", __func__, ret);
+ if (zclient_debug)
+ zlog_debug ("%s: Label manager connect request (%d bytes) sent", __func__, ret);
/* read response */
s = zclient->ibuf;
}
/* result */
result = stream_getc(s);
- zlog_debug ("%s: Label Manager connect response (%d bytes) received, result %u",
- __func__, size, result);
+ if (zclient_debug)
+ zlog_debug ("%s: Label Manager connect response (%d bytes) received, result %u",
+ __func__, size, result);
return (int)result;
}
u_int16_t cmd;
u_char response_keep;
- zlog_debug ("Getting Label Chunk");
+ if (zclient_debug)
+ zlog_debug ("Getting Label Chunk");
+
if (zclient->sock < 0)
return -1;
zclient->sock = -1;
return -1;
}
- zlog_debug ("%s: Label chunk request (%d bytes) sent", __func__, ret);
+ if (zclient_debug)
+ zlog_debug ("%s: Label chunk request (%d bytes) sent", __func__, ret);
/* read response */
s = zclient->ibuf;
zlog_err ("%s: Invalid Get Label Chunk Message Reply Header", __func__);
return -1;
}
- zlog_debug ("%s: Label chunk response (%d bytes) received", __func__, size);
+ if (zclient_debug)
+ zlog_debug ("%s: Label chunk response (%d bytes) received", __func__, size);
+
/* keep */
response_keep = stream_getc(s);
/* start and end labels */
return -1;
}
- zlog_debug ("Label Chunk assign: %u - %u (%u) ",
- *start, *end, response_keep);
+ if (zclient_debug)
+ zlog_debug ("Label Chunk assign: %u - %u (%u) ",
+ *start, *end, response_keep);
return 0;
}
int ret;
struct stream *s;
- zlog_debug ("Releasing Label Chunk");
+ if (zclient_debug)
+ zlog_debug ("Releasing Label Chunk");
+
if (zclient->sock < 0)
return -1;
if (nifp->ipsec_fallback_profile) free(nifp->ipsec_fallback_profile);
nifp->ipsec_fallback_profile = fallback_profile ? strdup(fallback_profile) : NULL;
+
+ notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_ADDRESS_CHANGED);
}
void nhrp_interface_set_source(struct interface *ifp, const char *ifname)
DEFINE_MTYPE_STATIC(NHRPD, NHRP_REGISTRATION, "NHRP registration entries")
static int nhrp_nhs_resolve(struct thread *t);
-
-struct nhrp_registration {
- struct list_head reglist_entry;
- struct thread *t_register;
- struct nhrp_nhs *nhs;
- struct nhrp_reqid reqid;
- unsigned int timeout;
- unsigned mark : 1;
- union sockunion proto_addr;
- struct nhrp_peer *peer;
- struct notifier_block peer_notifier;
-};
-
static int nhrp_reg_send_req(struct thread *t);
static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg)
}
}
}
+
+void nhrp_nhs_foreach(struct interface *ifp, afi_t afi, void (*cb)(struct nhrp_nhs *, struct nhrp_registration *, void *), void *ctx)
+{
+ struct nhrp_interface *nifp = ifp->info;
+ struct nhrp_nhs *nhs;
+ struct nhrp_registration *reg;
+
+ list_for_each_entry(nhs, &nifp->afi[afi].nhslist_head, nhslist_entry) {
+ if (!list_empty(&nhs->reglist_head)) {
+ list_for_each_entry(reg, &nhs->reglist_head, reglist_entry)
+ cb(nhs, reg, ctx);
+ } else
+ cb(nhs, 0, ctx);
+ }
+}
return 0;
if (p->requested)
return 0;
+ if (!nifp->ipsec_profile)
+ return 0;
if (sockunion_family(&vc->local.nbma) == AF_UNSPEC)
return 0;
reply ? buf[0] : buf[1]);
}
+static int proto2afi(uint16_t proto)
+{
+ switch (proto) {
+ case ETH_P_IP: return AFI_IP;
+ case ETH_P_IPV6: return AFI_IP6;
+ }
+ return AF_UNSPEC;
+}
+
struct nhrp_route_info {
int local;
struct interface *ifp;
const char *info = NULL;
union sockunion *target_addr;
unsigned paylen, extoff, extlen, realsize;
- afi_t afi;
+ afi_t nbma_afi, proto_afi;
debugf(NHRP_DEBUG_KERNEL, "PACKET: Recv %s -> %s",
sockunion2str(&vc->remote.nbma, buf[0], sizeof buf[0]),
pp.hdr = hdr;
pp.peer = p;
- afi = htons(hdr->afnum);
+ nbma_afi = htons(hdr->afnum);
+ proto_afi = proto2afi(htons(hdr->protocol_type));
if (hdr->type > ZEBRA_NUM_OF(packet_types) ||
hdr->version != NHRP_VERSION_RFC2332 ||
- afi >= AFI_MAX ||
+ nbma_afi >= AFI_MAX || proto_afi == AF_UNSPEC ||
packet_types[hdr->type].type == PACKET_UNKNOWN ||
htons(hdr->packet_size) > realsize) {
- zlog_info("From %s: error: packet type %d, version %d, AFI %d, size %d (real size %d)",
+ zlog_info("From %s: error: packet type %d, version %d, AFI %d, proto %x, size %d (real size %d)",
sockunion2str(&vc->remote.nbma, buf[0], sizeof buf[0]),
- (int) hdr->type, (int) hdr->version, (int) afi,
- (int) htons(hdr->packet_size),
- (int) realsize);
+ (int) hdr->type, (int) hdr->version,
+ (int) nbma_afi, (int) htons(hdr->protocol_type),
+ (int) htons(hdr->packet_size), (int) realsize);
goto drop;
}
- pp.if_ad = &((struct nhrp_interface *)ifp->info)->afi[afi];
+ pp.if_ad = &((struct nhrp_interface *)ifp->info)->afi[proto_afi];
extoff = htons(hdr->extension_offset);
if (extoff) {
extlen = zbuf_used(zb);
zbuf_init(&pp.extensions, zbuf_pulln(zb, extlen), extlen, extlen);
- if (!nifp->afi[afi].network_id) {
+ if (!nifp->afi[proto_afi].network_id) {
info = "nhrp not enabled";
goto drop;
}
return CMD_SUCCESS;
}
+DEFUN(if_no_nhrp_map, if_no_nhrp_map_cmd,
+ "no " AFI_CMD " nhrp map <A.B.C.D|X:X::X:X>",
+ NO_STR
+ AFI_STR
+ NHRP_STR
+ "Nexthop Server configuration\n"
+ "IPv4 protocol address\n"
+ "IPv6 protocol address\n")
+{
+ VTY_DECLVAR_CONTEXT(interface,ifp);
+ afi_t afi = cmd_to_afi(argv[1]);
+ union sockunion proto_addr;
+ struct nhrp_cache *c;
+
+ if (str2sockunion(argv[4]->arg, &proto_addr) < 0 ||
+ afi2family(afi) != sockunion_family(&proto_addr))
+ return nhrp_vty_return(vty, NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH);
+
+ c = nhrp_cache_get(ifp, &proto_addr, 0);
+ if (!c || !c->map)
+ return nhrp_vty_return(vty, NHRP_ERR_ENTRY_NOT_FOUND);
+
+ nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL);
+ return CMD_SUCCESS;
+}
+
DEFUN(if_nhrp_nhs, if_nhrp_nhs_cmd,
AFI_CMD " nhrp nhs <A.B.C.D|X:X::X:X|dynamic> nbma <A.B.C.D|FQDN>",
AFI_STR
VTY_NEWLINE);
}
+static void show_ip_nhrp_nhs(struct nhrp_nhs *n, struct nhrp_registration *reg, void *pctx)
+{
+ struct info_ctx *ctx = pctx;
+ struct vty *vty = ctx->vty;
+ char buf[2][SU_ADDRSTRLEN];
+
+ if (!ctx->count) {
+ vty_out(vty, "%-8s %-24s %-16s %-16s%s",
+ "Iface",
+ "FQDN",
+ "NBMA",
+ "Protocol",
+ VTY_NEWLINE);
+ }
+ ctx->count++;
+
+ vty_out(vty, "%-8s %-24s %-16s %-16s%s",
+ n->ifp->name,
+ n->nbma_fqdn,
+ (reg && reg->peer) ? sockunion2str(®->peer->vc->remote.nbma, buf[0], sizeof buf[0]) : "-",
+ sockunion2str(reg ? ®->proto_addr : &n->proto_addr, buf[1], sizeof buf[1]),
+ VTY_NEWLINE);
+}
+
+static void show_ip_nhrp_shortcut(struct nhrp_shortcut *s, void *pctx)
+{
+ struct info_ctx *ctx = pctx;
+ struct nhrp_cache *c;
+ struct vty *vty = ctx->vty;
+ char buf1[PREFIX_STRLEN], buf2[SU_ADDRSTRLEN];
+
+ if (!ctx->count) {
+ vty_out(vty, "%-8s %-24s %-24s %s%s",
+ "Type",
+ "Prefix",
+ "Via",
+ "Identity",
+ VTY_NEWLINE);
+ }
+ ctx->count++;
+
+ c = s->cache;
+ vty_out(ctx->vty, "%-8s %-24s %-24s %s%s",
+ nhrp_cache_type_str[s->type],
+ prefix2str(s->p, buf1, sizeof buf1),
+ c ? sockunion2str(&c->remote_addr, buf2, sizeof buf2) : "",
+ (c && c->cur.peer) ? c->cur.peer->vc->remote.id : "",
+ VTY_NEWLINE);
+}
+
static void show_ip_opennhrp_cache(struct nhrp_cache *c, void *pctx)
{
struct info_ctx *ctx = pctx;
vty_out(ctx->vty, "%s", VTY_NEWLINE);
}
-static void show_ip_nhrp_shortcut(struct nhrp_shortcut *s, void *pctx)
-{
- struct info_ctx *ctx = pctx;
- struct nhrp_cache *c;
- struct vty *vty = ctx->vty;
- char buf1[PREFIX_STRLEN], buf2[SU_ADDRSTRLEN];
-
- if (!ctx->count) {
- vty_out(vty, "%-8s %-24s %-24s %s%s",
- "Type",
- "Prefix",
- "Via",
- "Identity",
- VTY_NEWLINE);
- }
- ctx->count++;
-
- c = s->cache;
- vty_out(ctx->vty, "%-8s %-24s %-24s %s%s",
- nhrp_cache_type_str[s->type],
- prefix2str(s->p, buf1, sizeof buf1),
- c ? sockunion2str(&c->remote_addr, buf2, sizeof buf2) : "",
- (c && c->cur.peer) ? c->cur.peer->vc->remote.id : "",
- VTY_NEWLINE);
-}
-
DEFUN(show_ip_nhrp, show_ip_nhrp_cmd,
- "show " AFI_CMD " nhrp [cache|shortcut|opennhrp]",
+ "show " AFI_CMD " nhrp [cache|nhs|shortcut|opennhrp]",
SHOW_STR
AFI_STR
"NHRP information\n"
"Forwarding cache information\n"
+ "Next hop server information\n"
"Shortcut information\n"
"opennhrpctl style cache dump\n")
{
if (argc <= 3 || argv[3]->text[0] == 'c') {
for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp))
nhrp_cache_foreach(ifp, show_ip_nhrp_cache, &ctx);
- } else if (argv[3]->text[0] == 'o') {
+ } else if (argv[3]->text[0] == 'n') {
+ for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp))
+ nhrp_nhs_foreach(ifp, ctx.afi, show_ip_nhrp_nhs, &ctx);
+ } else if (argv[3]->text[0] == 's') {
+ nhrp_shortcut_foreach(ctx.afi, show_ip_nhrp_shortcut, &ctx);
+ } else {
vty_out(vty, "Status: ok%s%s", VTY_NEWLINE, VTY_NEWLINE);
ctx.count++;
for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp))
nhrp_cache_foreach(ifp, show_ip_opennhrp_cache, &ctx);
- } else {
- nhrp_shortcut_foreach(ctx.afi, show_ip_nhrp_shortcut, &ctx);
}
if (!ctx.count) {
install_element(INTERFACE_NODE, &if_nhrp_reg_flags_cmd);
install_element(INTERFACE_NODE, &if_no_nhrp_reg_flags_cmd);
install_element(INTERFACE_NODE, &if_nhrp_map_cmd);
+ install_element(INTERFACE_NODE, &if_no_nhrp_map_cmd);
install_element(INTERFACE_NODE, &if_nhrp_nhs_cmd);
install_element(INTERFACE_NODE, &if_no_nhrp_nhs_cmd);
}
struct list_head reglist_head;
};
+struct nhrp_registration {
+ struct list_head reglist_entry;
+ struct thread *t_register;
+ struct nhrp_nhs *nhs;
+ struct nhrp_reqid reqid;
+ unsigned int timeout;
+ unsigned mark : 1;
+ union sockunion proto_addr;
+ struct nhrp_peer *peer;
+ struct notifier_block peer_notifier;
+};
+
#define NHRP_IFF_SHORTCUT 0x0001
#define NHRP_IFF_REDIRECT 0x0002
#define NHRP_IFF_REG_NO_UNIQUE 0x0100
int nhrp_nhs_del(struct interface *ifp, afi_t afi, union sockunion *proto_addr, const char *nbma_fqdn);
int nhrp_nhs_free(struct nhrp_nhs *nhs);
void nhrp_nhs_terminate(void);
+void nhrp_nhs_foreach(struct interface *ifp, afi_t afi, void (*cb)(struct nhrp_nhs *, struct nhrp_registration *, void *), void *ctx);
void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp);
void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix *p, struct interface *ifp, const union sockunion *nexthop, uint32_t mtu);
}
}
+static void parse_cmd_response(
+ struct vici_message_ctx *ctx,
+ enum vici_type_t msgtype,
+ const struct blob *key, const struct blob *val)
+{
+ char buf[512];
+
+ switch (msgtype) {
+ case VICI_KEY_VALUE:
+ if (blob_equal(key, "errmsg") && blob2buf(val, buf, sizeof(buf)))
+ zlog_err("VICI: strongSwan: %s", buf);
+ break;
+ default:
+ break;
+ }
+}
+
static void vici_recv_sa(struct vici_conn *vici, struct zbuf *msg, int event)
{
char buf[32];
else if (blob_equal(&name, "child-state-destroying"))
vici_recv_sa(vici, msg, 2);
break;
+ case VICI_CMD_RESPONSE:
+ vici_parse_message(vici, msg, parse_cmd_response, 0);
+ break;
case VICI_EVENT_UNKNOWN:
+ case VICI_CMD_UNKNOWN:
zlog_err("VICI: StrongSwan does not support mandatory events (unpatched?)");
break;
case VICI_EVENT_CONFIRM:
- case VICI_CMD_RESPONSE:
break;
default:
zlog_notice("VICI: Unrecognized message type %d", msgtype);
vici_submit_request(
vici, "initiate",
VICI_KEY_VALUE, "child", strlen(profile), profile,
- VICI_KEY_VALUE, "timeout", 2, "-1",
- VICI_KEY_VALUE, "async", 1, "1",
- VICI_KEY_VALUE, "init-limits", 1, prio ? "0" : "1",
+ VICI_KEY_VALUE, "timeout", (size_t) 2, "-1",
+ VICI_KEY_VALUE, "async", (size_t) 1, "1",
+ VICI_KEY_VALUE, "init-limits", (size_t) 1, prio ? "0" : "1",
VICI_KEY_VALUE, "my-host", strlen(buf[0]), buf[0],
VICI_KEY_VALUE, "other-host", strlen(buf[1]), buf[1],
VICI_END);
ROUTER_STR
OSPF6_STR)
{
+ if (ospf6 == NULL)
+ vty_out (vty, "OSPFv3 is not configured%s", VNL);
+ else
+ {
+ ospf6_delete (ospf6);
+ ospf6 = NULL;
+ }
+
/* return to config node . */
VTY_PUSH_CONTEXT_NULL(CONFIG_NODE);
VTY_NEWLINE, VTY_NEWLINE);
}
- if (argc == (iface_argv + 1))
+ if (argc == iface_argv)
{
/* Show All Interfaces.*/
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
}
}
}
- else if (argv[iface_argv] && strcmp(argv[iface_argv]->arg, "json") == 0)
- {
- if (!use_json)
- {
- json = json_object_new_object();
- json_interface_sub = json_object_new_object ();
- use_json = 1;
- }
- /* Show All Interfaces. */
- for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
- {
- if (ospf_oi_count(ifp))
- {
- show_ip_ospf_interface_sub (vty, ospf, ifp, json_interface_sub, use_json);
- if (use_json)
- json_object_object_add(json, ifp->name, json_interface_sub);
- }
- }
- }
else
{
/* Interface name is specified. */
if ((ospf = ospf_lookup()) == NULL || !ospf->oi_running)
return CMD_SUCCESS;
- return show_ip_ospf_interface_common(vty, ospf, argc, argv, 0, uj);
+ if (uj)
+ argc--;
+
+ return show_ip_ospf_interface_common(vty, ospf, argc, argv, 4, uj);
}
DEFUN (show_ip_ospf_instance_interface,
if ((ospf = ospf_lookup_instance (instance)) == NULL || !ospf->oi_running)
return CMD_SUCCESS;
- return show_ip_ospf_interface_common(vty, ospf, argc, argv, 1, uj);
+ if (uj)
+ argc--;
+
+ return show_ip_ospf_interface_common(vty, ospf, argc, argv, 5, uj);
}
static void
#include "prefix.h"
#include "zclient.h"
#include "plist.h"
+#include "hash.h"
+#include "nexthop.h"
#include "pimd.h"
#include "pim_mroute.h"
#include "pim_zlookup.h"
#include "pim_msdp.h"
#include "pim_ssm.h"
+#include "pim_nht.h"
static struct cmd_node pim_global_node = {
PIM_NODE,
mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd);
if (uj) {
+ char pbuf[PREFIX2STR_BUFFER];
json_row = json_object_new_object();
json_object_pim_ifp_add(json_row, ifp);
sec_list = json_object_new_array();
for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, sec_node, sec_addr)) {
- json_object_array_add(sec_list, json_object_new_string(inet_ntoa(sec_addr->addr)));
+ json_object_array_add(sec_list,
+ json_object_new_string(prefix2str(&sec_addr->addr,
+ pbuf,
+ sizeof(pbuf))));
}
json_object_object_add(json_row, "secondaryAddressList", sec_list);
}
vty_out(vty, "Use Source : %s%s", inet_ntoa(pim_ifp->update_source), VTY_NEWLINE);
}
if (pim_ifp->sec_addr_list) {
+ char pbuf[PREFIX2STR_BUFFER];
vty_out(vty, "Address : %s (primary)%s",
- inet_ntoa(ifaddr), VTY_NEWLINE);
+ inet_ntoa(ifaddr), VTY_NEWLINE);
for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, sec_node, sec_addr)) {
vty_out(vty, " %s%s",
- inet_ntoa(sec_addr->addr), VTY_NEWLINE);
+ prefix2str(&sec_addr->addr,
+ pbuf,
+ sizeof(pbuf)), VTY_NEWLINE);
}
} else {
vty_out(vty, "Address : %s%s", inet_ntoa(ifaddr), VTY_NEWLINE);
struct pim_upstream *up;
int fhr = 0;
int pim_nbrs = 0;
+ int pim_ifchannels = 0;
json_object *json = NULL;
json_object *json_row = NULL;
json_object *json_tmp;
continue;
pim_nbrs = pim_ifp->pim_neighbor_list->count;
+ pim_ifchannels = pim_ifp->pim_ifchannel_list->count;
fhr = 0;
for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode, up))
json_row = json_object_new_object();
json_object_pim_ifp_add(json_row, ifp);
json_object_int_add(json_row, "pimNeighbors", pim_nbrs);
+ json_object_int_add(json_row, "pimIfChannels", pim_ifchannels);
json_object_int_add(json_row, "firstHopRouter", fhr);
json_object_string_add(json_row, "pimDesignatedRouter", inet_ntoa(pim_ifp->pim_dr_addr));
if (uj) {
vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
} else {
- vty_out(vty, "Interface State Address PIM Nbrs PIM DR FHR%s", VTY_NEWLINE);
+ vty_out(vty, "Interface State Address PIM Nbrs PIM DR FHR IfChannels%s", VTY_NEWLINE);
json_object_object_foreach(json, key, val) {
vty_out(vty, "%-9s ", key);
}
json_object_object_get_ex(val, "firstHopRouter", &json_tmp);
- vty_out(vty, "%3d%s", json_object_get_int(json_tmp), VTY_NEWLINE);
+ vty_out(vty, "%3d ", json_object_get_int(json_tmp));
+
+ json_object_object_get_ex(val, "pimIfChannels", &json_tmp);
+ vty_out(vty, "%9d%s", json_object_get_int(json_tmp), VTY_NEWLINE);
}
}
neigh_src_str, sizeof(neigh_src_str));
for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, prefix_node, p)) {
- char neigh_sec_str[INET_ADDRSTRLEN];
-
- if (p->family != AF_INET)
- continue;
+ char neigh_sec_str[PREFIX2STR_BUFFER];
- pim_inet4_dump("<src?>", p->u.prefix4,
- neigh_sec_str, sizeof(neigh_sec_str));
+ prefix2str(p, neigh_sec_str, sizeof(neigh_sec_str));
vty_out(vty, "%-9s %-15s %-15s %-15s%s",
ifp->name,
}
}
+static int
+pim_print_pnc_cache_walkcb (struct hash_backet *backet, void *arg)
+{
+ struct pim_nexthop_cache *pnc = backet->data;
+ struct vty *vty = arg;
+ struct nexthop *nh_node = NULL;
+ ifindex_t first_ifindex;
+ struct interface *ifp = NULL;
+
+ if (!pnc)
+ return CMD_SUCCESS;
+
+ for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next)
+ {
+ first_ifindex = nh_node->ifindex;
+ ifp = if_lookup_by_index (first_ifindex, VRF_DEFAULT);
+
+ vty_out (vty, "%-15s ", inet_ntoa (pnc->rpf.rpf_addr.u.prefix4));
+ vty_out (vty, "%-14s ", ifp ? ifp->name : "NULL");
+ vty_out (vty, "%s ", inet_ntoa (nh_node->gate.ipv4));
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ return CMD_SUCCESS;
+}
+
+static void
+pim_show_nexthop (struct vty *vty)
+{
+
+ if (pimg && !pimg->rpf_hash)
+ {
+ vty_out (vty, "no nexthop cache %s", VTY_NEWLINE);
+ return;
+ }
+
+ vty_out (vty, "Number of registered addresses: %lu %s",
+ pimg->rpf_hash->count, VTY_NEWLINE);
+ vty_out (vty, "Address Interface Nexthop%s", VTY_NEWLINE);
+ vty_out (vty, "-------------------------------------------%s", VTY_NEWLINE);
+
+ hash_walk (pimg->rpf_hash, pim_print_pnc_cache_walkcb, vty);
+
+}
+
static void igmp_show_groups(struct vty *vty, u_char uj)
{
struct listnode *ifnode;
return CMD_SUCCESS;
}
+DEFUN (show_ip_pim_nexthop,
+ show_ip_pim_nexthop_cmd,
+ "show ip pim nexthop",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ "PIM cached nexthop rpf information\n")
+{
+ pim_show_nexthop (vty);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_pim_nexthop_lookup,
+ show_ip_pim_nexthop_lookup_cmd,
+ "show ip pim nexthop-lookup A.B.C.D A.B.C.D",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ "PIM cached nexthop rpf lookup\n"
+ "Source/RP address\n"
+ "Multicast Group address\n")
+{
+ struct pim_nexthop_cache pnc;
+ struct prefix nht_p;
+ int result = 0;
+ struct in_addr src_addr, grp_addr;
+ struct in_addr vif_source;
+ const char *addr_str, *addr_str1;
+ struct prefix grp;
+ struct pim_nexthop nexthop;
+ char nexthop_addr_str[PREFIX_STRLEN];
+ char grp_str[PREFIX_STRLEN];
+
+ addr_str = (const char *)argv[0];
+ result = inet_pton (AF_INET, addr_str, &src_addr);
+ if (result <= 0)
+ {
+ vty_out (vty, "Bad unicast address %s: errno=%d: %s%s",
+ addr_str, errno, safe_strerror (errno), VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (pim_is_group_224_4 (src_addr))
+ {
+ vty_out (vty, "Invalid argument. Expected Valid Source Address.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ addr_str1 = (const char *)argv[1];
+ result = inet_pton (AF_INET, addr_str1, &grp_addr);
+ if (result <= 0)
+ {
+ vty_out (vty, "Bad unicast address %s: errno=%d: %s%s",
+ addr_str, errno, safe_strerror (errno), VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!pim_is_group_224_4 (grp_addr))
+ {
+ vty_out (vty, "Invalid argument. Expected Valid Multicast Group Address.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!pim_rp_set_upstream_addr (&vif_source, src_addr, grp_addr))
+ return CMD_SUCCESS;
+
+ memset (&pnc, 0, sizeof (struct pim_nexthop_cache));
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = vif_source;
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = grp_addr;
+ memset (&nexthop, 0, sizeof (nexthop));
+
+ if ((pim_find_or_track_nexthop (&nht_p, NULL, NULL, &pnc)) == 1)
+ {
+ //Compute PIM RPF using Cached nexthop
+ pim_ecmp_nexthop_search (&pnc, &nexthop, &nht_p, &grp, 0);
+ }
+ else
+ pim_ecmp_nexthop_lookup (&nexthop, vif_source, &nht_p, &grp, 0);
+
+ pim_addr_dump ("<grp?>", &grp, grp_str, sizeof (grp_str));
+ pim_addr_dump ("<nexthop?>", &nexthop.mrib_nexthop_addr,
+ nexthop_addr_str, sizeof (nexthop_addr_str));
+ vty_out (vty, "Group %s --- Nexthop %s Interface %s %s", grp_str,
+ nexthop_addr_str, nexthop.interface->name, VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
static void show_multicast_interfaces(struct vty *vty)
{
struct listnode *node;
PIM_MAX_USABLE_VIFS,
VTY_NEWLINE);
- vty_out(vty, "%s", VTY_NEWLINE);
- vty_out(vty, "Upstream Join Timer: %d secs%s",
- qpim_t_periodic,
- VTY_NEWLINE);
- vty_out(vty, "Join/Prune Holdtime: %d secs%s",
- PIM_JP_HOLDTIME,
- VTY_NEWLINE);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "Upstream Join Timer: %d secs%s",
+ qpim_t_periodic, VTY_NEWLINE);
+ vty_out (vty, "Join/Prune Holdtime: %d secs%s",
+ PIM_JP_HOLDTIME, VTY_NEWLINE);
+ vty_out (vty, "PIM ECMP: %s%s",
+ qpim_ecmp_enable ? "Enable" : "Disable", VTY_NEWLINE);
+ vty_out (vty, "PIM ECMP Rebalance: %s%s",
+ qpim_ecmp_rebalance_enable ? "Enable" : "Disable", VTY_NEWLINE);
- vty_out(vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "%s", VTY_NEWLINE);
show_rpf_refresh_stats(vty, now, NULL);
return CMD_SUCCESS;
}
+DEFUN (ip_pim_spt_switchover_infinity,
+ ip_pim_spt_switchover_infinity_cmd,
+ "ip pim spt-switchover infinity-and-beyond",
+ IP_STR
+ PIM_STR
+ "SPT-Switchover\n"
+ "Never switch to SPT Tree\n")
+{
+ pimg->spt_switchover = PIM_SPT_INFINITY;
+
+ pim_upstream_remove_lhr_star_pimreg();
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_pim_spt_switchover_infinity,
+ no_ip_pim_spt_switchover_infinity_cmd,
+ "no ip pim spt-switchover infinity-and-beyond",
+ NO_STR
+ IP_STR
+ PIM_STR
+ "SPT_Switchover\n"
+ "Never switch to SPT Tree\n")
+{
+ pimg->spt_switchover = PIM_SPT_IMMEDIATE;
+
+ pim_upstream_add_lhr_star_pimreg();
+ return CMD_SUCCESS;
+}
+
DEFUN (ip_pim_joinprune_time,
ip_pim_joinprune_time_cmd,
"ip pim join-prune-interval <60-600>",
return CMD_SUCCESS;
}
+DEFUN (ip_pim_v6_secondary,
+ ip_pim_v6_secondary_cmd,
+ "ip pim send-v6-secondary",
+ IP_STR
+ "pim multicast routing\n"
+ "Send v6 secondary addresses\n")
+{
+ pimg->send_v6_secondary = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_pim_v6_secondary,
+ no_ip_pim_v6_secondary_cmd,
+ "no ip pim send-v6-secondary",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Send v6 secondary addresses\n")
+{
+ pimg->send_v6_secondary = 0;
+
+ return CMD_SUCCESS;
+}
+
DEFUN (ip_pim_rp,
ip_pim_rp_cmd,
"ip pim rp A.B.C.D [A.B.C.D/M]",
"ip address of RP\n"
"Group Address range to cover\n")
{
- int idx_ipv4 = 4;
+ int idx_ipv4 = 4, idx_group = 0;
- if (argc == (idx_ipv4 + 1))
- return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, argv[idx_ipv4 + 1]->arg, NULL);
+ if (argv_find (argv, argc, "A.B.C.D/M", &idx_group))
+ return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, argv[idx_group]->arg, NULL);
else
return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, NULL, NULL);
}
return CMD_SUCCESS;
}
+DEFUN (ip_pim_ecmp,
+ ip_pim_ecmp_cmd,
+ "ip pim ecmp",
+ IP_STR
+ "pim multicast routing\n"
+ "Enable PIM ECMP \n")
+{
+ qpim_ecmp_enable = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_pim_ecmp,
+ no_ip_pim_ecmp_cmd,
+ "no ip pim ecmp",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Disable PIM ECMP \n")
+{
+ qpim_ecmp_enable = 0;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (ip_pim_ecmp_rebalance,
+ ip_pim_ecmp_rebalance_cmd,
+ "ip pim ecmp rebalance",
+ IP_STR
+ "pim multicast routing\n"
+ "Enable PIM ECMP \n"
+ "Enable PIM ECMP Rebalance\n")
+{
+ qpim_ecmp_rebalance_enable = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_pim_ecmp_rebalance,
+ no_ip_pim_ecmp_rebalance_cmd,
+ "no ip pim ecmp rebalance",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Disable PIM ECMP \n"
+ "Disable PIM ECMP Rebalance\n")
+{
+ qpim_ecmp_rebalance_enable = 0;
+
+ return CMD_SUCCESS;
+}
+
static int
pim_cmd_igmp_start (struct vty *vty, struct interface *ifp)
{
"JavaScript Object Notation\n")
{
u_char uj = use_json(argc, argv);
- if (uj)
- argc--;
- if (argc == 5)
- ip_msdp_show_sa_sg(vty, argv[4]->arg, argv[5]->arg, uj);
- else if (argc == 4)
- ip_msdp_show_sa_addr(vty, argv[4]->arg, uj);
+ int idx = 0;
+ char *src_ip = argv_find (argv, argc, "A.B.C.D", &idx) ? argv[idx++]->arg : NULL;
+ char *grp_ip = idx < argc && argv_find (argv, argc, "A.B.C.D", &idx) ?
+ argv[idx]->arg : NULL;
+
+ if (src_ip && grp_ip)
+ ip_msdp_show_sa_sg(vty, src_ip, grp_ip, uj);
+ else if (src_ip)
+ ip_msdp_show_sa_addr(vty, src_ip, uj);
else
ip_msdp_show_sa(vty, uj);
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_spt_switchover_infinity_cmd);
+ install_element (CONFIG_NODE, &no_ip_pim_spt_switchover_infinity_cmd);
install_element (CONFIG_NODE, &ip_pim_joinprune_time_cmd);
install_element (CONFIG_NODE, &no_ip_pim_joinprune_time_cmd);
install_element (CONFIG_NODE, &ip_pim_keep_alive_cmd);
install_element (CONFIG_NODE, &no_ip_pim_keep_alive_cmd);
install_element (CONFIG_NODE, &ip_pim_packets_cmd);
install_element (CONFIG_NODE, &no_ip_pim_packets_cmd);
+ install_element (CONFIG_NODE, &ip_pim_v6_secondary_cmd);
+ install_element (CONFIG_NODE, &no_ip_pim_v6_secondary_cmd);
install_element (CONFIG_NODE, &ip_ssmpingd_cmd);
install_element (CONFIG_NODE, &no_ip_ssmpingd_cmd);
install_element (CONFIG_NODE, &ip_msdp_peer_cmd);
install_element (CONFIG_NODE, &no_ip_msdp_peer_cmd);
+ install_element (CONFIG_NODE, &ip_pim_ecmp_cmd);
+ install_element (CONFIG_NODE, &no_ip_pim_ecmp_cmd);
+ install_element (CONFIG_NODE, &ip_pim_ecmp_rebalance_cmd);
+ install_element (CONFIG_NODE, &no_ip_pim_ecmp_rebalance_cmd);
install_element (INTERFACE_NODE, &interface_ip_igmp_cmd);
install_element (INTERFACE_NODE, &interface_no_ip_igmp_cmd);
install_element (VIEW_NODE, &show_ip_rib_cmd);
install_element (VIEW_NODE, &show_ip_ssmpingd_cmd);
install_element (VIEW_NODE, &show_debugging_pim_cmd);
+ install_element (VIEW_NODE, &show_ip_pim_nexthop_cmd);
+ install_element (VIEW_NODE, &show_ip_pim_nexthop_lookup_cmd);
install_element (ENABLE_NODE, &clear_ip_interfaces_cmd);
install_element (ENABLE_NODE, &clear_ip_igmp_interfaces_cmd);
return 0;
}
-int pim_hello_build_tlv(const char *ifname,
+int pim_hello_build_tlv(struct interface *ifp,
uint8_t *tlv_buf, int tlv_buf_size,
uint16_t holdtime,
uint32_t dr_priority,
uint32_t generation_id,
uint16_t propagation_delay,
uint16_t override_interval,
- int can_disable_join_suppression,
- struct list *ifconnected)
+ int can_disable_join_suppression)
{
uint8_t *curr = tlv_buf;
uint8_t *pastend = tlv_buf + tlv_buf_size;
if (!curr) {
if (PIM_DEBUG_PIM_HELLO) {
zlog_debug("%s: could not set PIM hello Holdtime option for interface %s",
- __PRETTY_FUNCTION__, ifname);
+ __PRETTY_FUNCTION__, ifp->name);
}
return -1;
}
if (!tmp) {
if (PIM_DEBUG_PIM_HELLO) {
zlog_debug("%s: could not set PIM LAN Prune Delay option for interface %s",
- __PRETTY_FUNCTION__, ifname);
+ __PRETTY_FUNCTION__, ifp->name);
}
return -1;
}
if (!curr) {
if (PIM_DEBUG_PIM_HELLO) {
zlog_debug("%s: could not set PIM hello DR Priority option for interface %s",
- __PRETTY_FUNCTION__, ifname);
+ __PRETTY_FUNCTION__, ifp->name);
}
return -2;
}
if (!curr) {
if (PIM_DEBUG_PIM_HELLO) {
zlog_debug("%s: could not set PIM hello Generation ID option for interface %s",
- __PRETTY_FUNCTION__, ifname);
+ __PRETTY_FUNCTION__, ifp->name);
}
return -3;
}
/* Secondary Address List */
- if (ifconnected) {
+ if (ifp->connected->count) {
curr = pim_tlv_append_addrlist_ucast(curr,
pastend,
- ifconnected);
+ ifp->connected,
+ AF_INET);
if (!curr) {
if (PIM_DEBUG_PIM_HELLO) {
- zlog_debug("%s: could not set PIM hello Secondary Address List option for interface %s",
- __PRETTY_FUNCTION__, ifname);
+ zlog_debug("%s: could not set PIM hello v4 Secondary Address List option for interface %s",
+ __PRETTY_FUNCTION__, ifp->name);
}
return -4;
}
+ if (pimg->send_v6_secondary)
+ {
+ curr = pim_tlv_append_addrlist_ucast(curr,
+ pastend,
+ ifp->connected,
+ AF_INET6);
+ if (!curr) {
+ if (PIM_DEBUG_PIM_HELLO) {
+ zlog_debug("%s: could not sent PIM hello v6 secondary Address List option for interface %s",
+ __PRETTY_FUNCTION__, ifp->name);
+ }
+ return -4;
+ }
+ }
}
return curr - tlv_buf;
struct in_addr src_addr,
uint8_t *tlv_buf, int tlv_buf_size);
-int pim_hello_build_tlv(const char *ifname,
+int pim_hello_build_tlv(struct interface *ifp,
uint8_t *tlv_buf, int tlv_buf_size,
uint16_t holdtime,
uint32_t dr_priority,
uint32_t generation_id,
uint16_t propagation_delay,
uint16_t override_interval,
- int can_disable_join_suppression,
- struct list *ifconnected);
+ int can_disable_join_suppression);
void pim_hello_require(struct interface *ifp);
#include "hash.h"
#include "pimd.h"
+#include "pim_zebra.h"
#include "pim_iface.h"
#include "pim_igmp.h"
#include "pim_mroute.h"
#include "pim_time.h"
#include "pim_ssmpingd.h"
#include "pim_rp.h"
+#include "pim_nht.h"
struct interface *pim_regiface = NULL;
struct list *pim_ifchannel_list = NULL;
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))
+ if (sec1->addr.family == AF_INET &&
+ sec2->addr.family == AF_INET6)
return -1;
- if (ntohl(sec1->addr.s_addr) > ntohl(sec2->addr.s_addr))
+ if (sec1->addr.family == AF_INET6 &&
+ sec2->addr.family == AF_INET)
return 1;
+ if (sec1->addr.family == AF_INET)
+ {
+ if (ntohl(sec1->addr.u.prefix4.s_addr) < ntohl(sec2->addr.u.prefix4.s_addr))
+ return -1;
+
+ if (ntohl(sec1->addr.u.prefix4.s_addr) > ntohl(sec2->addr.u.prefix4.s_addr))
+ return 1;
+ }
+ else
+ {
+ return memcmp (&sec1->addr.u.prefix6,
+ &sec2->addr.u.prefix6,
+ sizeof (struct in6_addr));
+ }
+
return 0;
}
}
static struct pim_secondary_addr *
-pim_sec_addr_find(struct pim_interface *pim_ifp, struct in_addr addr)
+pim_sec_addr_find(struct pim_interface *pim_ifp, struct prefix *addr)
{
struct pim_secondary_addr *sec_addr;
struct listnode *node;
}
for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
- if (sec_addr->addr.s_addr == addr.s_addr) {
+ if (prefix_cmp(&sec_addr->addr, addr)) {
return sec_addr;
}
}
pim_sec_addr_free(sec_addr);
}
-static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct in_addr addr)
+static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct prefix *addr)
{
int changed = 0;
struct pim_secondary_addr *sec_addr;
}
changed = 1;
- sec_addr->addr = addr;
+ sec_addr->addr = *addr;
listnode_add_sort(pim_ifp->sec_addr_list, sec_addr);
return changed;
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;
}
continue;
}
- if (pim_sec_addr_add(pim_ifp, p->u.prefix4)) {
+ if (pim_sec_addr_add(pim_ifp, p)) {
changed = 1;
}
}
detect_address_change(ifp, 0, __PRETTY_FUNCTION__);
+ if (ifc->address->family != AF_INET)
+ return;
+
if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
struct igmp_sock *igmp;
/* lookup IGMP socket */
igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
- ifaddr);
+ ifaddr);
if (!igmp) {
/* if addr new, add IGMP socket */
pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp);
}
} /* igmp */
- 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);
- }
- }
+ if (PIM_IF_TEST_PIM(pim_ifp->options))
+ {
- }
- } /* pim */
+ 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);
+ }
+ }
+ struct pim_nexthop_cache *pnc = NULL;
+ struct pim_rpf rpf;
+ struct zclient *zclient = NULL;
+
+ zclient = pim_zebra_zclient_get ();
+ /* RP config might come prior to (local RP's interface) IF UP event.
+ In this case, pnc would not have pim enabled nexthops.
+ Once Interface is UP and pim info is available, reregister
+ with RNH address to receive update and add the interface as nexthop. */
+ memset (&rpf, 0, sizeof (struct pim_rpf));
+ rpf.rpf_addr.family = AF_INET;
+ rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN;
+ rpf.rpf_addr.u.prefix4 = ifc->address->u.prefix4;
+ pnc = pim_nexthop_cache_find (&rpf);
+ if (pnc)
+ pim_sendmsg_zebra_rnh (zclient, pnc,
+ ZEBRA_NEXTHOP_REGISTER);
+ }
+ } /* pim */
/*
PIM or IGMP is enabled on interface, and there is at least one
ifp = ifc->ifp;
zassert(ifp);
+ if (ifc->address->family != AF_INET)
+ return;
+
if (PIM_DEBUG_ZEBRA) {
char buf[BUFSIZ];
prefix2str(ifc->address, buf, BUFSIZ);
zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
- __PRETTY_FUNCTION__,
- ifp->name, ifp->ifindex, buf,
- CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
- "secondary" : "primary");
+ __PRETTY_FUNCTION__,
+ ifp->name, ifp->ifindex, buf,
+ CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
+ "secondary" : "primary");
}
detect_address_change(ifp, force_prim_as_any, __PRETTY_FUNCTION__);
struct prefix *p = ifc->address;
if (p->family != AF_INET)
- {
- v6_addrs++;
- continue;
- }
-
- v4_addrs++;
+ v6_addrs++;
+ else
+ v4_addrs++;
pim_if_addr_add(ifc);
}
struct listnode *neighnode;
struct pim_neighbor *neigh;
struct pim_interface *pim_ifp;
+ struct prefix p;
zassert(ifp);
return 0;
}
+ p.family = AF_INET;
+ p.u.prefix4 = addr;
+ p.prefixlen = IPV4_MAX_PREFIXLEN;
+
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) {
/* primary address ? */
return neigh;
/* secondary address ? */
- if (pim_neighbor_find_secondary(neigh, addr))
+ if (pim_neighbor_find_secondary(neigh, &p))
return neigh;
}
};
struct pim_secondary_addr {
- struct in_addr addr;
+ struct prefix addr;
enum pim_secondary_addr_flags flags;
};
pim_upstream_switch (child, PIM_UPSTREAM_JOINED);
}
}
+ if (pimg->spt_switchover != PIM_SPT_INFINITY)
+ pim_channel_add_oif(up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP);
}
return 1;
up->channel_oil->cc.pktcnt++;
PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
+ // resolve mfcc_parent prior to mroute_add in channel_add_oif
+ if (up->channel_oil->oil.mfcc_parent >= MAXVIFS)
+ {
+ int vif_index = 0;
+ vif_index =
+ pim_if_find_vifindex_by_ifindex (up->rpf.source_nexthop.
+ interface->ifindex);
+ up->channel_oil->oil.mfcc_parent = vif_index;
+ }
pim_register_join (up);
return 0;
up = pim_upstream_find(&sg);
if (!up) {
+ struct prefix_sg star = sg;
+ star.src.s_addr = INADDR_ANY;
+
+ up = pim_upstream_find(&star);
+
+ if (up && PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags))
+ {
+ up = pim_upstream_add (&sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_LHR, __PRETTY_FUNCTION__);
+ if (!up)
+ {
+ if (PIM_DEBUG_MROUTE)
+ zlog_debug ("%s: Unable to create upstream information for %s",
+ __PRETTY_FUNCTION__, pim_str_sg_dump (&sg));
+ return 0;
+ }
+ pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
+ pim_upstream_inherited_olist (up);
+ pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
+
+ if (PIM_DEBUG_MROUTE)
+ zlog_debug ("%s: Creating %s upstream on LHR",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return 0;
+ }
if (PIM_DEBUG_MROUTE_DETAIL) {
zlog_debug("%s: Unable to find upstream channel WHOLEPKT%s",
__PRETTY_FUNCTION__, pim_str_sg_dump (&sg));
pim_channel_oil_dump (c_oil, buf, sizeof(buf)));
}
- /*reset incoming vifi and kernel installed flags*/
+ //Reset kernel installed flag
c_oil->installed = 0;
- c_oil->oil.mfcc_parent = MAXVIFS;
return 0;
}
From:
http://www.iana.org/assignments/address-family-numbers
*/
-#define PIM_MSG_ADDRESS_FAMILY_IPV4 (1)
+enum pim_msg_address_family {
+ PIM_MSG_ADDRESS_FAMILY_RESERVED,
+ PIM_MSG_ADDRESS_FAMILY_IPV4,
+ PIM_MSG_ADDRESS_FAMILY_IPV6,
+};
/*
* Network Order pim_msg_hdr
XFREE(MTYPE_PIM_NEIGHBOR, neigh);
}
+struct pim_neighbor *
+pim_neighbor_find_by_secondary (struct interface *ifp,
+ struct prefix *src)
+{
+ struct pim_interface *pim_ifp;
+ struct listnode *node, *pnode;
+ struct pim_neighbor *neigh;
+ struct prefix *p;
+
+ pim_ifp = ifp->info;
+ if (!pim_ifp)
+ return NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh))
+ {
+ for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, pnode, p))
+ {
+ if (prefix_same (p, src))
+ return neigh;
+ }
+ }
+
+ return NULL;
+}
+
struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
struct in_addr source_addr)
{
listnode_add(pim_ifp->pim_neighbor_list, neigh);
+ if (PIM_DEBUG_PIM_TRACE_DETAIL)
+ {
+ char str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<nht_nbr?>", source_addr, str, sizeof (str));
+ zlog_debug ("%s: neighbor %s added ", __PRETTY_FUNCTION__, str);
+ }
/*
RFC 4601: 4.3.2. DR Election
pim_upstream_find_new_rpf();
+ /* RNH can send nexthop update prior to PIM neibhor UP
+ in that case nexthop cache would not consider this neighbor
+ as RPF.
+ Upon PIM neighbor UP, iterate all RPs and update
+ nexthop cache with this neighbor.
+ */
+ pim_resolve_rp_nh ();
+
pim_rp_setup ();
pim_neighbor_rpf_update();
}
struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
- struct in_addr addr)
+ struct prefix *addr)
{
struct listnode *node;
struct prefix *p;
return 0;
for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) {
- if (p->family == AF_INET) {
- if (addr.s_addr == p->u.prefix4.s_addr) {
- return p;
- }
- }
+ if (prefix_same (p, addr))
+ return p;
}
- return 0;
+ return NULL;
}
/*
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node,
neigh)) {
{
- struct prefix *p = pim_neighbor_find_secondary(neigh, addr->u.prefix4);
+ struct prefix *p = pim_neighbor_find_secondary(neigh, addr);
if (p) {
char addr_str[INET_ADDRSTRLEN];
char this_neigh_str[INET_ADDRSTRLEN];
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_by_secondary (struct interface *ifp,
+ struct prefix *src);
struct pim_neighbor *pim_neighbor_find_if (struct interface *ifp);
uint32_t dr_priority,
struct list *addr_list);
struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
- struct in_addr addr);
+ struct prefix *addr);
int pim_if_dr_election(struct interface *ifp);
#endif /* PIM_NEIGHBOR_H */
#include "pim_join.h"
#include "pim_jp_agg.h"
#include "pim_zebra.h"
+#include "pim_zlookup.h"
/**
* pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
* command to Zebra.
*/
-static void
+void
pim_sendmsg_zebra_rnh (struct zclient *zclient, struct pim_nexthop_cache *pnc,
int command)
{
{
char buf[PREFIX2STR_BUFFER];
prefix2str (p, buf, sizeof (buf));
- zlog_debug ("%s: NHT Addr %s %sregistered with Zebra ret:%d ",
- __PRETTY_FUNCTION__, buf,
- (command == ZEBRA_NEXTHOP_REGISTER) ? " " : "de", ret);
+ zlog_debug ("%s: NHT %sregistered addr %s with Zebra ret:%d ",
+ __PRETTY_FUNCTION__,
+ (command == ZEBRA_NEXTHOP_REGISTER) ? " " : "de", buf, ret);
}
return;
/* This API is used to Register an address with Zebra */
int
pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up,
- struct rp_info *rp)
+ struct rp_info *rp,
+ struct pim_nexthop_cache *out_pnc)
{
struct pim_nexthop_cache *pnc = NULL;
struct pim_rpf rpf;
}
pnc = pim_nexthop_cache_add (&rpf);
if (pnc)
- pim_sendmsg_zebra_rnh (zclient, pnc,
- ZEBRA_NEXTHOP_REGISTER);
+ pim_sendmsg_zebra_rnh (zclient, pnc, ZEBRA_NEXTHOP_REGISTER);
else
{
- zlog_warn ("%s: pnc node allocation failed. ", __PRETTY_FUNCTION__);
+ char rpf_str[PREFIX_STRLEN];
+ pim_addr_dump ("<nht-pnc?>", addr, rpf_str, sizeof (rpf_str));
+ zlog_warn ("%s: pnc node allocation failed. addr %s ",
+ __PRETTY_FUNCTION__, rpf_str);
+ return -1;
}
}
char rp_str[PREFIX_STRLEN];
pim_addr_dump ("<rp?>", &rp->rp.rpf_addr, rp_str,
sizeof (rp_str));
- zlog_debug ("%s: NHT add RP %s node to cached list",
+ zlog_debug ("%s: Add RP %s node to pnc cached list",
__PRETTY_FUNCTION__, rp_str);
}
listnode_add_sort (pnc->rp_list, rp);
char buf[PREFIX2STR_BUFFER];
prefix2str (addr, buf, sizeof (buf));
zlog_debug
- ("%s: NHT add upstream %s node to cached list, rpf %s",
+ ("%s: Add upstream %s node to pnc cached list, rpf %s",
__PRETTY_FUNCTION__, up->sg_str, buf);
}
listnode_add_sort (pnc->upstream_list, up);
}
}
- if (CHECK_FLAG (pnc->flags, PIM_NEXTHOP_VALID))
- return 1;
+ if (pnc && CHECK_FLAG (pnc->flags, PIM_NEXTHOP_VALID))
+ {
+ memcpy (out_pnc, pnc, sizeof (struct pim_nexthop_cache));
+ return 1;
+ }
return 0;
}
if (pnc->rp_list->count == 0 && pnc->upstream_list->count == 0)
{
- pim_sendmsg_zebra_rnh (zclient, pnc,
- ZEBRA_NEXTHOP_UNREGISTER);
+ pim_sendmsg_zebra_rnh (zclient, pnc, ZEBRA_NEXTHOP_UNREGISTER);
list_delete (pnc->rp_list);
list_delete (pnc->upstream_list);
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++;
- continue;
- }
+ //Compute PIM RPF using cached nexthop
+ pim_ecmp_nexthop_search (pnc, &rp_info->rp.source_nexthop,
+ &rp_info->rp.rpf_addr, &rp_info->group, 1);
if (PIM_DEBUG_TRACE)
{
char rp_str[PREFIX_STRLEN];
pim_addr_dump ("<rp?>", &rp_info->rp.rpf_addr, rp_str,
sizeof (rp_str));
- zlog_debug ("%s: NHT update nexthop for RP %s to interface %s ",
+ zlog_debug ("%s: NHT update, nexthop for RP %s is interface %s ",
__PRETTY_FUNCTION__, rp_str,
rp_info->rp.source_nexthop.interface->name);
}
}
+/* This API is used to traverse nexthop cache of RPF addr
+ of upstream entry whose IPv4 nexthop address is in
+ unresolved state and due to event like pim neighbor
+ UP event if it can be resolved.
+*/
+void
+pim_resolve_upstream_nh (struct prefix *nht_p)
+{
+ struct nexthop *nh_node = NULL;
+ struct pim_nexthop_cache pnc;
+ struct pim_neighbor *nbr = NULL;
+
+ memset (&pnc, 0, sizeof (struct pim_nexthop_cache));
+ if ((pim_find_or_track_nexthop (nht_p, NULL, NULL, &pnc)) == 1)
+ {
+ for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next)
+ {
+ if (nh_node->gate.ipv4.s_addr == 0)
+ {
+ nbr =
+ pim_neighbor_find_if (if_lookup_by_index
+ (nh_node->ifindex, VRF_DEFAULT));
+ if (nbr)
+ {
+ nh_node->gate.ipv4 = nbr->source_addr;
+ if (PIM_DEBUG_TRACE)
+ {
+ char str[PREFIX_STRLEN];
+ char str1[INET_ADDRSTRLEN];
+ pim_inet4_dump ("<nht_nbr?>", nbr->source_addr, str1,
+ sizeof (str1));
+ pim_addr_dump ("<nht_addr?>", nht_p, str, sizeof (str));
+ zlog_debug
+ ("%s: addr %s new nexthop addr %s ifindex %d ",
+ __PRETTY_FUNCTION__, str, str1, nh_node->ifindex);
+ }
+ }
+ }
+ }
+ }
+}
+
/* Update Upstream nexthop info based on Nexthop update received from Zebra.*/
static int
pim_update_upstream_nh (struct pim_nexthop_cache *pnc)
struct listnode *ifnode;
struct listnode *up_nextnode;
struct listnode *node;
- struct pim_upstream *up;
- struct interface *ifp;
+ struct pim_upstream *up = NULL;
+ struct interface *ifp = NULL;
int vif_index = 0;
for (ALL_LIST_ELEMENTS (pnc->upstream_list, up_node, up_nextnode, up))
if (rpf_result == PIM_RPF_FAILURE)
continue;
+ /* update kernel multicast forwarding cache (MFC) */
+ if (up->channel_oil)
+ {
+ vif_index =
+ pim_if_find_vifindex_by_ifindex (up->rpf.
+ source_nexthop.interface->
+ ifindex);
+ /* Pass Current selected NH vif index to mroute download */
+ if (vif_index)
+ pim_scan_individual_oil (up->channel_oil, vif_index);
+ else
+ {
+ if (PIM_DEBUG_ZEBRA)
+ zlog_debug
+ ("%s: NHT upstream %s channel_oil IIF %s vif_index is not valid",
+ __PRETTY_FUNCTION__, up->sg_str,
+ up->rpf.source_nexthop.interface->name);
+ }
+ }
+
if (rpf_result == PIM_RPF_CHANGED)
{
struct pim_neighbor *nbr;
returning PIM_RPF_CHANGED ? */
pim_upstream_update_join_desired (up);
- } /* PIM_RPF_CHANGED */
+ } /* PIM_RPF_CHANGED */
if (PIM_DEBUG_TRACE)
{
old.source_nexthop.interface->name,
up->rpf.source_nexthop.interface->name);
}
- /* update kernel multicast forwarding cache (MFC) */
- if (up->channel_oil)
- {
- vif_index =
- pim_if_find_vifindex_by_ifindex (up->rpf.
- source_nexthop.interface->
- ifindex);
- /* Pass Current selected NH vif index to mroute download */
- if (vif_index)
- pim_scan_individual_oil (up->channel_oil, vif_index);
- else
- {
- if (PIM_DEBUG_ZEBRA)
- zlog_debug ("%s: NHT upstream %s channel_oil IIF %s vif_index is not valid",
- __PRETTY_FUNCTION__, up->sg_str,
- up->rpf.source_nexthop.interface->name);
- }
- }
-
- } /* for (pnc->upstream_list) */
+ } /* for (pnc->upstream_list) */
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp))
if (ifp->info)
return 0;
}
-/*
- * This API is used to parse Registered address nexthop update
- * coming from Zebra
- */
+uint32_t
+pim_compute_ecmp_hash (struct prefix * src, struct prefix * grp)
+{
+ uint32_t hash_val;
+ uint32_t s = 0, g = 0;
+
+ if ((!src))
+ return 0;
+
+ switch (src->family)
+ {
+ case AF_INET:
+ {
+ s = src->u.prefix4.s_addr;
+ s = s == 0 ? 1 : s;
+ if (grp)
+ g = grp->u.prefix4.s_addr;
+ }
+ break;
+ default:
+ break;
+ }
+
+ hash_val = jhash_2words (g, s, 101);
+ if (PIM_DEBUG_TRACE)
+ {
+ char buf[PREFIX2STR_BUFFER];
+ char bufg[PREFIX2STR_BUFFER];
+ prefix2str (src, buf, sizeof (buf));
+ if (grp)
+ prefix2str (grp, bufg, sizeof (bufg));
+ zlog_debug ("%s: addr %s %s hash_val %u", __PRETTY_FUNCTION__, buf,
+ grp ? bufg : "", hash_val);
+
+ }
+ return hash_val;
+}
+
+int
+pim_ecmp_nexthop_search (struct pim_nexthop_cache *pnc,
+ struct pim_nexthop *nexthop, struct prefix *src,
+ struct prefix *grp, int neighbor_needed)
+{
+ struct pim_neighbor *nbr = NULL;
+ struct nexthop *nh_node = NULL;
+ ifindex_t first_ifindex;
+ struct interface *ifp = NULL;
+ uint32_t hash_val = 0, mod_val = 0;
+ uint8_t nh_iter = 0, found = 0;
+
+ if (!pnc || !pnc->nexthop_num || !nexthop)
+ return -1;
+
+ if (qpim_ecmp_enable)
+ {
+ //User configured knob to explicitly switch to new path.
+ if (qpim_ecmp_rebalance_enable == 0)
+ {
+ //Current Nexthop is VALID then stay on the current path.
+ if (nexthop->interface && nexthop->interface->info &&
+ nexthop->mrib_nexthop_addr.u.prefix4.s_addr !=
+ PIM_NET_INADDR_ANY)
+ {
+ if (neighbor_needed
+ && !pim_if_connected_to_source (nexthop->interface,
+ src->u.prefix4))
+ {
+ nbr = pim_neighbor_find (nexthop->interface,
+ nexthop->mrib_nexthop_addr.
+ u.prefix4);
+ if (!nbr && !if_is_loopback (nexthop->interface))
+ {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: current nexthop does not have nbr ",
+ __PRETTY_FUNCTION__);
+ }
+ else
+ {
+ if (PIM_DEBUG_TRACE)
+ {
+ char src_str[INET_ADDRSTRLEN];
+ pim_inet4_dump ("<addr?>", src->u.prefix4, src_str,
+ sizeof (src_str));
+ char grp_str[INET_ADDRSTRLEN];
+ pim_inet4_dump ("<addr?>", grp->u.prefix4, grp_str,
+ sizeof (grp_str));
+ zlog_debug
+ ("%s: %s %s current nexthop %d is valid, not choosing new path",
+ __PRETTY_FUNCTION__, src_str, grp_str,
+ nexthop->interface->ifindex);
+ }
+ return 0;
+ }
+ }
+ }
+ }
+ //PIM ECMP flag is enable then choose ECMP path.
+ hash_val = pim_compute_ecmp_hash (src, grp);
+ mod_val = hash_val % pnc->nexthop_num;
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: hash_val %u mod_val %u ",
+ __PRETTY_FUNCTION__, hash_val, mod_val);
+ }
+
+ for (nh_node = pnc->nexthop; nh_node && (found == 0);
+ nh_node = nh_node->next)
+ {
+ first_ifindex = nh_node->ifindex;
+ ifp = if_lookup_by_index (first_ifindex, VRF_DEFAULT);
+ if (!ifp)
+ {
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char addr_str[INET_ADDRSTRLEN];
+ pim_inet4_dump ("<addr?>", src->u.prefix4, 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);
+ }
+ if (nh_iter == mod_val)
+ mod_val++; //Select nexthpath
+ nh_iter++;
+ continue;
+ }
+ if (!ifp->info)
+ {
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char addr_str[INET_ADDRSTRLEN];
+ pim_inet4_dump ("<addr?>", src->u.prefix4, 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);
+ }
+ if (nh_iter == mod_val)
+ mod_val++; //Select nexthpath
+ nh_iter++;
+ continue;
+ }
+
+ if (neighbor_needed
+ && !pim_if_connected_to_source (ifp, src->u.prefix4))
+ {
+ nbr = pim_neighbor_find (ifp, nh_node->gate.ipv4);
+ if (PIM_DEBUG_PIM_TRACE_DETAIL)
+ zlog_debug ("ifp name: %s, pim nbr: %p", ifp->name, nbr);
+ if (!nbr && !if_is_loopback (ifp))
+ {
+ if (PIM_DEBUG_ZEBRA)
+ zlog_debug
+ ("%s: pim nbr not found on input interface %s",
+ __PRETTY_FUNCTION__, ifp->name);
+ if (nh_iter == mod_val)
+ mod_val++; //Select nexthpath
+ nh_iter++;
+ continue;
+ }
+ }
+
+ if (nh_iter == mod_val)
+ {
+ nexthop->interface = ifp;
+ nexthop->mrib_nexthop_addr.family = AF_INET;
+ nexthop->mrib_nexthop_addr.prefixlen = IPV4_MAX_BITLEN;
+ nexthop->mrib_nexthop_addr.u.prefix4 = nh_node->gate.ipv4;
+ nexthop->mrib_metric_preference = pnc->distance;
+ nexthop->mrib_route_metric = pnc->metric;
+ nexthop->last_lookup = src->u.prefix4;
+ nexthop->last_lookup_time = pim_time_monotonic_usec ();
+ nexthop->nbr = nbr;
+ found = 1;
+
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char buf[NEXTHOP_STRLEN];
+ char buf2[PREFIX2STR_BUFFER];
+ char buf3[PREFIX2STR_BUFFER];
+ char buf4[PREFIX2STR_BUFFER];
+ pim_inet4_dump ("<src?>", src->u.prefix4, buf2, sizeof (buf2));
+ if (grp)
+ pim_inet4_dump ("<src?>", grp->u.prefix4, buf3,
+ sizeof (buf3));
+ pim_inet4_dump ("<rpf?>",
+ nexthop->mrib_nexthop_addr.u.prefix4, buf4,
+ sizeof (buf4));
+ snprintf (buf, sizeof (buf), "%s if %u",
+ inet_ntoa (nh_node->gate.ipv4), nh_node->ifindex);
+ zlog_debug
+ ("%s: NHT %s %s selected nhop interface %s nhop %s (%s) mod_val:%u iter:%d ecmp_enable:%d",
+ __PRETTY_FUNCTION__, buf2, grp ? buf3 : " ", ifp->name,
+ buf, buf4, mod_val, nh_iter, qpim_ecmp_enable);
+ }
+ }
+ nh_iter++;
+
+ }
+
+ return 0;
+}
+
+/* This API is used to parse Registered address nexthop update coming from Zebra */
int
pim_parse_nexthop_update (int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
struct stream *s;
struct prefix p;
struct nexthop *nexthop;
- struct nexthop *oldnh;
struct nexthop *nhlist_head = NULL;
struct nexthop *nhlist_tail = NULL;
uint32_t metric, distance;
{
char buf[PREFIX2STR_BUFFER];
prefix2str (&rpf.rpf_addr, buf, sizeof (buf));
- zlog_debug ("%s: NHT addr %s is not in local cached DB.",
- __PRETTY_FUNCTION__, buf);
+ zlog_debug
+ ("%s: Skipping NHT update, addr %s is not in local cached DB.",
+ __PRETTY_FUNCTION__, buf);
}
return 0;
}
return 0;
}
- pnc->last_update = pim_time_monotonic_sec ();
+ pnc->last_update = pim_time_monotonic_usec ();
distance = stream_getc (s);
metric = stream_getl (s);
nexthop_num = stream_getc (s);
{
char buf[PREFIX2STR_BUFFER];
prefix2str (&p, buf, sizeof (buf));
- zlog_debug ("%s: NHT Update for %s nexthop_num %d vrf:%d upcount %d rpcount %d",
- __PRETTY_FUNCTION__, buf, nexthop_num, vrf_id,
- listcount (pnc->upstream_list), listcount (pnc->rp_list));
+ zlog_debug
+ ("%s: NHT Update for %s nexthop_num %d vrf:%d upcount %d rpcount %d",
+ __PRETTY_FUNCTION__, buf, nexthop_num, vrf_id,
+ listcount (pnc->upstream_list), listcount (pnc->rp_list));
}
if (nexthop_num)
{
- pnc->flags |= PIM_NEXTHOP_VALID;
- pnc->distance = distance;
- pnc->metric = metric;
- pnc->nexthop_num = nexthop_num;
+ pnc->nexthop_num = 0; //Only increment for pim enabled rpf.
for (i = 0; i < nexthop_num; i++)
{
(nexthop->ifindex, VRF_DEFAULT));
/* Overwrite with Nbr address as NH addr */
if (nbr)
- nexthop->gate.ipv4 = nbr->source_addr;
+ {
+ nexthop->gate.ipv4 = nbr->source_addr;
+ if (PIM_DEBUG_TRACE)
+ {
+ char str[INET_ADDRSTRLEN];
+ pim_inet4_dump ("<nht_nbr?>", nbr->source_addr, str,
+ sizeof (str));
+ zlog_debug
+ ("%s: NHT using pim nbr addr %s ifindex %d as rpf",
+ __PRETTY_FUNCTION__, str, nexthop->ifindex);
+ }
+ }
+ else
+ {
+ if (PIM_DEBUG_TRACE)
+ {
+ struct interface *ifp1 =
+ if_lookup_by_index (nexthop->ifindex,
+ VRF_DEFAULT);
+ struct pim_interface *pim_ifp = ifp1->info;
+ zlog_debug
+ ("%s: NHT pim nbr not found on interface %s nbr count:%d ",
+ __PRETTY_FUNCTION__, ifp1->name,
+ pim_ifp->pim_neighbor_list->count);
+ }
+ //Mark nexthop address to 0 until PIM Nbr is resolved.
+ nexthop->gate.ipv4.s_addr = PIM_NET_INADDR_ANY;
+ }
break;
default:
if (PIM_DEBUG_ZEBRA)
{
char buf[NEXTHOP_STRLEN];
- zlog_debug("%s: could not find interface for ifindex %d (addr %s)",
- __PRETTY_FUNCTION__,
- nexthop->ifindex, nexthop2str (nexthop, buf, sizeof (buf)));
+ zlog_debug
+ ("%s: could not find interface for ifindex %d (addr %s)",
+ __PRETTY_FUNCTION__, nexthop->ifindex,
+ nexthop2str (nexthop, buf, sizeof (buf)));
}
nexthop_free (nexthop);
continue;
nhlist_tail = nexthop;
nhlist_head = nexthop;
}
-
- for (oldnh = pnc->nexthop; oldnh; oldnh = oldnh->next)
- if (nexthop_same_no_recurse (oldnh, nexthop))
- break;
+ //Only keep track of nexthops which are PIM enabled.
+ pnc->nexthop_num++;
}
/* Reset existing pnc->nexthop before assigning new list */
nexthops_free (pnc->nexthop);
pnc->nexthop = nhlist_head;
+ if (pnc->nexthop_num)
+ {
+ pnc->flags |= PIM_NEXTHOP_VALID;
+ pnc->distance = distance;
+ pnc->metric = metric;
+ }
}
else
{
pnc->nexthop = NULL;
}
+ if (PIM_DEBUG_TRACE)
+ {
+ char buf[PREFIX2STR_BUFFER];
+ prefix2str (&p, buf, sizeof (buf));
+ zlog_debug
+ ("%s: NHT Update for %s nexthop_num:%d pim nexthop_num %d vrf:%d up %d rp %d",
+ __PRETTY_FUNCTION__, buf, nexthop_num, pnc->nexthop_num, vrf_id,
+ listcount (pnc->upstream_list), listcount (pnc->rp_list));
+ }
+
pim_rpf_set_refresh_time ();
if (listcount (pnc->rp_list))
return 0;
}
+
+int
+pim_ecmp_nexthop_lookup (struct pim_nexthop *nexthop, struct in_addr addr,
+ struct prefix *src, struct prefix *grp,
+ int neighbor_needed)
+{
+ struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
+ struct pim_neighbor *nbr = NULL;
+ int num_ifindex;
+ struct interface *ifp;
+ int first_ifindex;
+ int found = 0;
+ uint8_t i = 0;
+ uint32_t hash_val = 0, mod_val = 0;
+
+ 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",
+ __PRETTY_FUNCTION__, addr_str, nexthop->last_lookup_time);
+ }
+
+ 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 %s: could not find nexthop ifindex for address %s",
+ __FILE__, __PRETTY_FUNCTION__, addr_str);
+ return -1;
+ }
+
+ //If PIM ECMP enable then choose ECMP path
+ if (qpim_ecmp_enable)
+ {
+ hash_val = pim_compute_ecmp_hash (src, grp);
+ mod_val = hash_val % num_ifindex;
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: hash_val %u mod_val %u ",
+ __PRETTY_FUNCTION__, hash_val, mod_val);
+ }
+
+ while (!found && (i < num_ifindex))
+ {
+ first_ifindex = nexthop_tab[i].ifindex;
+
+ ifp = if_lookup_by_index (first_ifindex, VRF_DEFAULT);
+ 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);
+ }
+ if (i == mod_val)
+ mod_val++;
+ i++;
+ continue;
+ }
+
+ 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);
+ }
+ if (i == mod_val)
+ mod_val++;
+ i++;
+ continue;
+ }
+ if (neighbor_needed && !pim_if_connected_to_source (ifp, addr))
+ {
+ 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))
+ {
+ if (i == mod_val)
+ mod_val++;
+ i++;
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char addr_str[INET_ADDRSTRLEN];
+ pim_inet4_dump ("<addr?>", addr, addr_str,
+ sizeof (addr_str));
+ zlog_debug
+ ("%s: NBR not found on input interface %s (RPF for source %s)",
+ __PRETTY_FUNCTION__, ifp->name, addr_str);
+ }
+ continue;
+ }
+ }
+
+ if (i == mod_val)
+ {
+ 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 addr %s interface %s metric=%d pref=%d",
+ __FILE__, __PRETTY_FUNCTION__, nexthop_str, addr_str,
+ ifp->name, 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();
+ nexthop->nbr = nbr;
+ found = 1;
+ }
+ i++;
+ }
+ if (found)
+ return 0;
+ else
+ return -1;
+}
int pim_parse_nexthop_update (int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id);
int pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up,
- struct rp_info *rp);
+ struct rp_info *rp, struct pim_nexthop_cache *out_pnc);
void pim_delete_tracked_nexthop (struct prefix *addr, struct pim_upstream *up,
struct rp_info *rp);
struct pim_nexthop_cache *pim_nexthop_cache_add (struct pim_rpf *rpf_addr);
struct pim_nexthop_cache *pim_nexthop_cache_find (struct pim_rpf *rpf);
-
+uint32_t pim_compute_ecmp_hash (struct prefix *src, struct prefix *grp);
+int pim_ecmp_nexthop_search (struct pim_nexthop_cache * pnc,
+ struct pim_nexthop *nexthop, struct prefix *src,
+ struct prefix *grp, int neighbor_needed);
+int pim_ecmp_nexthop_lookup (struct pim_nexthop *nexthop, struct in_addr addr,
+ struct prefix *src, struct prefix *grp,
+ int neighbor_needed);
+void pim_sendmsg_zebra_rnh (struct zclient *zclient, struct pim_nexthop_cache *pnc,
+ int command);
+void pim_resolve_upstream_nh (struct prefix *nht_p);
#endif
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",
+ zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u IIF:%d OIF=%s vif_index=%d",
__FILE__, __PRETTY_FUNCTION__,
source_str, group_str,
- proto_mask, oif->name, pim_ifp->mroute_vif_index);
+ proto_mask, channel_oil->oil.mfcc_parent ,oif->name, pim_ifp->mroute_vif_index);
}
return 0;
listcount(ifp->connected));
}
- pim_tlv_size = pim_hello_build_tlv(ifp->name,
+ pim_tlv_size = pim_hello_build_tlv(ifp,
pim_msg + PIM_PIM_MIN_LEN,
sizeof(pim_msg) - PIM_PIM_MIN_LEN,
holdtime,
pim_ifp->pim_generation_id,
pim_ifp->pim_propagation_delay_msec,
pim_ifp->pim_override_interval_msec,
- PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
- ifp->connected);
+ PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options));
if (pim_tlv_size < 0) {
return -1;
}
return;
}
+ if (PIM_DEBUG_PIM_REG)
+ {
+ char rp_str[INET_ADDRSTRLEN];
+ strcpy (rp_str, inet_ntoa (rpg->rpf_addr.u.prefix4));
+ zlog_debug ("%s: Sending %s %sRegister Packet to %s on %s",
+ __PRETTY_FUNCTION__, up->sg_str,
+ null_register ? "NULL " : "", rp_str, ifp->name);
+ }
+
memset(buffer, 0, 10000);
b1 = buffer + PIM_MSG_HEADER_LEN;
*b1 |= null_register << 6;
#include "vty.h"
#include "vrf.h"
#include "plist.h"
+#include "nexthop.h"
#include "pimd.h"
#include "pim_vty.h"
}
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) {
+ if (prefix_same(&sec_addr->addr, &rp_info->rp.rpf_addr)) {
return 1;
}
}
int
pim_rp_new (const char *rp, const char *group_range, const char *plist)
{
- int result;
+ int result, ret = 0;
struct rp_info *rp_info;
struct rp_info *rp_all;
struct prefix group_all;
struct rp_info *tmp_rp_info;
char buffer[BUFSIZ];
struct prefix nht_p;
+ struct pim_nexthop_cache pnc;
rp_info = XCALLOC (MTYPE_PIM_RP, sizeof (*rp_info));
if (!rp_info)
/* Register addr with Zebra NHT */
nht_p.family = AF_INET;
nht_p.prefixlen = IPV4_MAX_BITLEN;
- nht_p.u.prefix4 = rp_all->rp.rpf_addr.u.prefix4;
+ nht_p.u.prefix4 = rp_all->rp.rpf_addr.u.prefix4; //RP address
if (PIM_DEBUG_PIM_TRACE)
{
char buf[PREFIX2STR_BUFFER];
+ char buf1[PREFIX2STR_BUFFER];
prefix2str (&nht_p, buf, sizeof (buf));
- zlog_debug ("%s: NHT Register rp_all addr %s with NHT ",
- __PRETTY_FUNCTION__, buf);
+ prefix2str (&rp_all->group, buf1, sizeof (buf1));
+ zlog_debug ("%s: NHT Register rp_all addr %s grp %s ",
+ __PRETTY_FUNCTION__, buf, buf1);
+ }
+ memset (&pnc, 0, sizeof (struct pim_nexthop_cache));
+ if ((ret =
+ pim_find_or_track_nexthop (&nht_p, NULL, rp_all, &pnc)) == 1)
+ {
+ //Compute PIM RPF using Cached nexthop
+ pim_ecmp_nexthop_search (&pnc, &rp_all->rp.source_nexthop,
+ &nht_p, &rp_all->group, 1);
+ }
+ else
+ {
+ if (pim_nexthop_lookup (&rp_all->rp.source_nexthop, rp_all->rp.rpf_addr.u.prefix4, 1) != 0)
+ return PIM_RP_NO_PATH;
}
- pim_find_or_track_nexthop (&nht_p, NULL, rp_all);
-
- 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();
+ pim_rp_refresh_group_to_rp_mapping ();
return PIM_SUCCESS;
}
if (PIM_DEBUG_PIM_TRACE)
{
char buf[PREFIX2STR_BUFFER];
+ char buf1[PREFIX2STR_BUFFER];
prefix2str (&nht_p, buf, sizeof (buf));
- zlog_debug ("%s: NHT Register RP addr %s with Zebra ", __PRETTY_FUNCTION__, buf);
+ prefix2str (&rp_info->group, buf1, sizeof (buf1));
+ zlog_debug ("%s: NHT Register RP addr %s grp %s with Zebra ",
+ __PRETTY_FUNCTION__, buf, buf1);
}
- pim_find_or_track_nexthop (&nht_p, NULL, 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;
+ memset (&pnc, 0, sizeof (struct pim_nexthop_cache));
+ if ((ret = pim_find_or_track_nexthop (&nht_p, NULL, rp_info, &pnc)) == 1)
+ {
+ //Compute PIM RPF using Cached nexthop
+ pim_ecmp_nexthop_search (&pnc, &rp_info->rp.source_nexthop,
+ &nht_p, &rp_info->group, 1);
+ }
+ else
+ {
+ 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 ();
{
char buf[PREFIX2STR_BUFFER];
prefix2str (&nht_p, buf, sizeof (buf));
- zlog_debug ("%s: Deregister RP addr %s with NHT ", __PRETTY_FUNCTION__, buf);
+ zlog_debug ("%s: Deregister RP addr %s with Zebra ", __PRETTY_FUNCTION__,
+ buf);
}
pim_delete_tracked_nexthop (&nht_p, NULL, rp_info);
struct listnode *node;
struct rp_info *rp_info;
int ret = 0;
+ struct prefix nht_p;
+ struct pim_nexthop_cache pnc;
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)
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
+ memset (&pnc, 0, sizeof (struct pim_nexthop_cache));
+ if ((pim_find_or_track_nexthop (&nht_p, NULL, rp_info, &pnc)) == 1)
{
- if (PIM_DEBUG_PIM_TRACE)
- zlog_debug ("Unable to lookup nexthop for rp specified");
- ret++;
+ //Compute PIM RPF using Cached nexthop
+ pim_ecmp_nexthop_search (&pnc, &rp_info->rp.source_nexthop,
+ &nht_p, &rp_info->group, 1);
+ }
+ else
+ {
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char buf[PREFIX2STR_BUFFER];
+ prefix2str (&nht_p, buf, sizeof (buf));
+ zlog_debug ("%s: NHT Local Nexthop not found for RP %s ",
+ __PRETTY_FUNCTION__, buf);
+ }
+ 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 (rp_info)
{
- pim_nexthop_lookup(&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1);
+ int ret = 0;
+ struct prefix nht_p;
+ struct pim_nexthop_cache pnc;
+ /* Register addr with Zebra NHT */
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
+ if (PIM_DEBUG_PIM_TRACE)
+ {
+ char buf[PREFIX2STR_BUFFER];
+ char buf1[PREFIX2STR_BUFFER];
+ prefix2str (&nht_p, buf, sizeof (buf));
+ prefix2str (&rp_info->group, buf1, sizeof (buf1));
+ zlog_debug ("%s: NHT Register RP addr %s grp %s with Zebra ",
+ __PRETTY_FUNCTION__, buf, buf1);
+ }
+ memset (&pnc, 0, sizeof (struct pim_nexthop_cache));
+ if ((ret = pim_find_or_track_nexthop (&nht_p, NULL, rp_info, &pnc)) == 1)
+ {
+ //Compute PIM RPF using Cached nexthop
+ pim_ecmp_nexthop_search (&pnc, &rp_info->rp.source_nexthop,
+ &nht_p, &rp_info->group, 1);
+ }
+ else
+ {
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char buf[PREFIX2STR_BUFFER];
+ char buf1[PREFIX2STR_BUFFER];
+ prefix2str (&nht_p, buf, sizeof (buf));
+ prefix2str (&g, buf1, sizeof (buf1));
+ zlog_debug ("%s: NHT nexthop cache not found for RP %s grp %s",
+ __PRETTY_FUNCTION__, buf, buf1);
+ }
+ pim_rpf_set_refresh_time ();
+ pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1);
+ }
return (&rp_info->rp);
}
json_object_free(json);
}
}
+
+void
+pim_resolve_rp_nh (void)
+{
+ struct listnode *node = NULL;
+ struct rp_info *rp_info = NULL;
+ struct nexthop *nh_node = NULL;
+ struct prefix nht_p;
+ struct pim_nexthop_cache pnc;
+ struct pim_neighbor *nbr = NULL;
+
+ for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
+ {
+ if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
+ continue;
+
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
+ memset (&pnc, 0, sizeof (struct pim_nexthop_cache));
+ if ((pim_find_or_track_nexthop (&nht_p, NULL, rp_info, &pnc)) == 1)
+ {
+ for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next)
+ {
+ if (nh_node->gate.ipv4.s_addr == 0)
+ {
+ nbr =
+ pim_neighbor_find_if (if_lookup_by_index
+ (nh_node->ifindex, VRF_DEFAULT));
+ if (nbr)
+ {
+ nh_node->gate.ipv4 = nbr->source_addr;
+ if (PIM_DEBUG_TRACE)
+ {
+ char str[PREFIX_STRLEN];
+ char str1[INET_ADDRSTRLEN];
+ pim_inet4_dump ("<nht_nbr?>", nbr->source_addr,
+ str1, sizeof (str1));
+ pim_addr_dump ("<nht_addr?>", &nht_p, str,
+ sizeof (str));
+ zlog_debug
+ ("%s: addr %s new nexthop addr %s ifindex %d ",
+ __PRETTY_FUNCTION__, str, str1,
+ nh_node->ifindex);
+ }
+ }
+ }
+ }
+ }
+ }
+}
#define RP(G) pim_rp_g ((G))
void pim_rp_show_information (struct vty *vty, u_char uj);
-
+void pim_resolve_rp_nh (void);
int pim_rp_list_cmp (void *v1, void *v2);
#endif
{
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",
+ char nexthop_str[PREFIX_STRLEN];
+ pim_addr_dump("<nexthop?>", &nexthop->mrib_nexthop_addr,
+ nexthop_str, sizeof(nexthop_str));
+ zlog_debug ("%s: Using last lookup for %s at %lld, %lld addr%s",
__PRETTY_FUNCTION__,
addr_str,
nexthop->last_lookup_time,
- last_route_change_time);
+ last_route_change_time, nexthop_str);
}
nexthop_lookups_avoided++;
return 0;
struct pim_rpf *rpf = &up->rpf;
struct pim_rpf saved;
struct prefix nht_p;
+ struct pim_nexthop_cache pnc;
+ int ret = 0;
+ struct prefix src, grp;
saved.source_nexthop = rpf->source_nexthop;
saved.rpf_addr = rpf->rpf_addr;
- if (is_new)
+ if (is_new && PIM_DEBUG_ZEBRA)
+ {
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump ("<source?>", up->upstream_addr, source_str,
+ sizeof (source_str));
+ zlog_debug ("%s: NHT Register upstream %s addr %s with Zebra.",
+ __PRETTY_FUNCTION__, up->sg_str, source_str);
+ }
+ /* Register addr with Zebra NHT */
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
+
+ src.family = AF_INET;
+ src.prefixlen = IPV4_MAX_BITLEN;
+ src.u.prefix4 = up->upstream_addr; //RP or Src address
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = up->sg.grp;
+ memset (&pnc, 0, sizeof (struct pim_nexthop_cache));
+ if ((ret = pim_find_or_track_nexthop (&nht_p, up, NULL, &pnc)) == 1)
{
- if (PIM_DEBUG_ZEBRA)
+ if (pnc.nexthop_num)
{
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<source?>", up->upstream_addr, source_str, sizeof(source_str));
- zlog_debug ("%s: NHT Register upstream %s addr %s with Zebra.",
- __PRETTY_FUNCTION__, up->sg_str, source_str);
+ //Compute PIM RPF using Cached nexthop
+ pim_ecmp_nexthop_search (&pnc, &up->rpf.source_nexthop,
+ &src, &grp,
+ !PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) &&
+ !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->
+ flags));
}
- /* Register addr with Zebra NHT */
- nht_p.family = AF_INET;
- nht_p.prefixlen = IPV4_MAX_BITLEN;
- nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
- pim_find_or_track_nexthop (&nht_p, up, NULL);
}
-
- if (pim_nexthop_lookup(&rpf->source_nexthop,
- up->upstream_addr,
- !PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) &&
- !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags))) {
- return PIM_RPF_FAILURE;
- }
+ else
+ {
+ if (pim_ecmp_nexthop_lookup (&rpf->source_nexthop,
+ up->upstream_addr, &src, &grp,
+ !PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) &&
+ !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->
+ flags)))
+ {
+ return PIM_RPF_FAILURE;
+ }
+ }
rpf->rpf_addr.family = AF_INET;
rpf->rpf_addr.u.prefix4 = pim_rpf_find_rpf_addr(up);
}
#define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
+#define ucast_ipv6_encoding_len (2 + sizeof(struct in6_addr))
/*
* An Encoded-Unicast address takes the following format:
memcpy (buf, &p->u.prefix4, sizeof (struct in_addr));
return ucast_ipv4_encoding_len;
break;
+ case AF_INET6:
+ *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV6;
+ ++buf;
+ *(uint8_t *)buf = 0;
+ ++buf;
+ memcpy (buf, &p->u.prefix6, sizeof (struct in6_addr));
+ return ucast_ipv6_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)
+ struct list *ifconnected,
+ int family)
{
struct listnode *node;
uint16_t option_len = 0;
-
uint8_t *curr;
+ size_t uel;
node = listhead(ifconnected);
return buf;
}
- /* Skip first address (primary) */
- node = listnextnode(node);
+ if (family == AF_INET)
+ uel = ucast_ipv4_encoding_len;
+ else
+ uel = ucast_ipv6_encoding_len;
/* Scan secondary address list */
curr = buf + 4; /* skip T and L */
struct prefix *p = ifc->address;
int l_encode;
- if ((curr + ucast_ipv4_encoding_len) > buf_pastend)
- return 0;
+ if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
+ continue;
+
+ if ((curr + uel) > buf_pastend)
+ return 0;
+
+ if (p->family != family)
+ continue;
l_encode = pim_encode_addr_ucast (curr, p);
curr += l_encode;
if (PIM_DEBUG_PIM_TRACE_DETAIL) {
zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu",
__PRETTY_FUNCTION__,
- option_len / ucast_ipv4_encoding_len);
+ option_len / uel);
}
if (option_len < 1) {
p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
-
+ p->prefixlen = IPV4_MAX_PREFIXLEN;
addr += sizeof(struct in_addr);
+ break;
+ case PIM_MSG_ADDRESS_FAMILY_IPV6:
+ if ((addr + sizeof(struct in6_addr)) > pastend) {
+ zlog_warn ("%s: IPv6 unicast address overflow: left=%zd needed %zu",
+ __PRETTY_FUNCTION__,
+ pastend - addr, sizeof(struct in6_addr));
+ return -3;
+ }
+
+ p->family = AF_INET6;
+ p->prefixlen = IPV6_MAX_PREFIXLEN;
+ memcpy(&p->u.prefix6, addr, sizeof(struct in6_addr));
+ addr += sizeof(struct in6_addr);
+
break;
default:
{
addr_str, src_str, ifname);
}
break;
+ case AF_INET6:
+ break;
default:
{
char src_str[INET_ADDRSTRLEN];
FREE_ADDR_LIST(*hello_option_addr_list);
return -3;
}
- p->family = tmp.family;
- p->u.prefix4 = tmp.u.prefix4;
+ prefix_copy(p, &tmp);
listnode_add(*hello_option_addr_list, p);
}
uint32_t option_value);
uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
const uint8_t *buf_pastend,
- struct list *ifconnected);
+ struct list *ifconnected,
+ int family);
int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr,
pim_hello_options *hello_options,
upstream_channel_oil_detach(up);
if (up->sources)
- list_delete (up->sources);
+ {
+ struct listnode *node, *nnode;
+ struct pim_upstream *child;
+ for (ALL_LIST_ELEMENTS (up->sources, node, nnode, child))
+ {
+ if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(child->flags))
+ {
+ PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(child->flags);
+ pim_upstream_del(child, __PRETTY_FUNCTION__);
+ }
+ }
+
+ list_delete (up->sources);
+ }
up->sources = NULL;
/*
{
char buf[PREFIX2STR_BUFFER];
prefix2str (&nht_p, buf, sizeof (buf));
- zlog_debug ("%s: Deregister upstream %s upstream addr %s with NHT ",
- __PRETTY_FUNCTION__, up->sg_str, buf);
+ zlog_debug ("%s: Deregister upstream %s addr %s with Zebra",
+ __PRETTY_FUNCTION__, up->sg_str, buf);
}
pim_delete_tracked_nexthop (&nht_p, up, NULL);
return NULL;
}
- pim_ifp = up->rpf.source_nexthop.interface->info;
- if (pim_ifp)
- up->channel_oil = pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index);
-
+ if (up->rpf.source_nexthop.interface)
+ {
+ pim_ifp = up->rpf.source_nexthop.interface->info;
+ if (pim_ifp)
+ up->channel_oil = pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index);
+ }
listnode_add_sort(pim_upstream_list, up);
if (PIM_DEBUG_TRACE)
if (PIM_DEBUG_TRACE)
{
if (up)
- zlog_debug("%s(%s): %s, found: %d: ref_count: %d",
+ {
+ char buf[PREFIX2STR_BUFFER];
+ prefix2str (&up->rpf.rpf_addr, buf, sizeof (buf));
+ zlog_debug("%s(%s): %s, iif %s found: %d: ref_count: %d",
__PRETTY_FUNCTION__, name,
- up->sg_str, found,
+ up->sg_str, buf, found,
up->ref_count);
+ }
else
zlog_debug("%s(%s): (%s) failure to create",
__PRETTY_FUNCTION__, name,
up->t_ka_timer = NULL;
if (I_am_RP (up->sg.grp))
- {
- pim_br_clear_pmbr (&up->sg);
- /*
- * We need to do more here :)
- * But this is the start.
- */
- }
+ {
+ pim_br_clear_pmbr (&up->sg);
+ /*
+ * We need to do more here :)
+ * But this is the start.
+ */
+ }
/* source is no longer active - pull the SA from MSDP's cache */
pim_msdp_sa_local_del(&up->sg);
/* if entry was created because of activity we need to deref it */
if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
- {
- pim_upstream_fhr_kat_expiry(up);
- if (PIM_DEBUG_TRACE)
- zlog_debug ("kat expired on %s; remove stream reference", up->sg_str);
- PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
- pim_upstream_del(up, __PRETTY_FUNCTION__);
- }
+ {
+ pim_upstream_fhr_kat_expiry(up);
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("kat expired on %s; remove stream reference", up->sg_str);
+ PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
+ pim_upstream_del(up, __PRETTY_FUNCTION__);
+ }
+ else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags))
+ {
+ PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags);
+ pim_upstream_del(up, __PRETTY_FUNCTION__);
+ }
return 0;
}
return;
}
- if (pim_upstream_kat_start_ok(up)) {
- /* Add a source reference to the stream if
- * one doesn't already exist */
- if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
+ if (pim_upstream_kat_start_ok(up))
{
- if (PIM_DEBUG_TRACE)
- zlog_debug ("source reference created on kat restart %s", up->sg_str);
+ /* Add a source reference to the stream if
+ * one doesn't already exist */
+ if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
+ {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("source reference created on kat restart %s", up->sg_str);
- pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM);
- PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
- pim_upstream_fhr_kat_start(up);
+ pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM);
+ PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
+ pim_upstream_fhr_kat_start(up);
+ }
+ pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
}
+ else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags))
pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
- }
if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE)
- {
- pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
- }
+ {
+ pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
+ }
return;
}
+void
+pim_upstream_add_lhr_star_pimreg (void)
+{
+ struct pim_upstream *up;
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, node, up))
+ {
+ if (up->sg.src.s_addr != INADDR_ANY)
+ continue;
+
+ if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags))
+ continue;
+
+ pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP);
+ }
+}
+
+void
+pim_upstream_remove_lhr_star_pimreg (void)
+{
+ struct pim_upstream *up;
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, node, up))
+ {
+ if (up->sg.src.s_addr != INADDR_ANY)
+ continue;
+
+ if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags))
+ continue;
+
+ pim_channel_del_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP);
+ }
+}
+
void
pim_upstream_init (void)
{
#define PIM_UPSTREAM_FLAG_MASK_SRC_STREAM (1 << 5)
#define PIM_UPSTREAM_FLAG_MASK_SRC_MSDP (1 << 6)
#define PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE (1 << 7)
+#define PIM_UPSTREAM_FLAG_MASK_SRC_LHR (1 << 8)
+#define PIM_UPSTREAM_FLAG_ALL 0xFFFFFFFF
#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_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_TEST_SEND_SG_RPT_PRUNE(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE)
+#define PIM_UPSTREAM_FLAG_TEST_SRC_LHR(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_LHR)
#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_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_SET_SEND_SG_RPT_PRUNE(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE)
+#define PIM_UPSTREAM_FLAG_SET_SRC_LHR(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_LHR)
#define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
#define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
#define PIM_UPSTREAM_FLAG_UNSET_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)
#define PIM_UPSTREAM_FLAG_UNSET_SEND_SG_RPT_PRUNE(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE)
+#define PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_LHR)
enum pim_upstream_state {
PIM_UPSTREAM_NOTJOINED,
void join_timer_start (struct pim_upstream *up);
int pim_upstream_compare (void *arg1, void *arg2);
void pim_upstream_register_reevaluate (void);
+
+void pim_upstream_add_lhr_star_pimreg (void);
+void pim_upstream_remove_lhr_star_pimreg (void);
#endif /* PIM_UPSTREAM_H */
writes += pim_msdp_config_write (vty);
+ if (!pimg->send_v6_secondary)
+ {
+ vty_out (vty, "no ip pim send-v6-secondary%s", VTY_NEWLINE);
+ ++writes;
+ }
+
writes += pim_rp_config_write (vty);
if (qpim_register_suppress_time != PIM_REGISTER_SUPPRESSION_TIME_DEFAULT)
ssm->plist_name, VTY_NEWLINE);
++writes;
}
+ if (pimg->spt_switchover == PIM_SPT_INFINITY)
+ {
+ vty_out (vty, "ip pim spt-switchover infinity-and-beyond%s",
+ VTY_NEWLINE);
+ ++writes;
+ }
if (qpim_ssmpingd_list) {
struct listnode *node;
#endif
}
- 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 */
struct in_addr primary_addr = pim_find_primary_addr(c->ifp);
- if (primary_addr.s_addr != p->u.prefix4.s_addr) {
+ if (p->family != AF_INET || primary_addr.s_addr != p->u.prefix4.s_addr) {
if (PIM_DEBUG_ZEBRA) {
/* but we had a primary address already */
for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
enum pim_rpf_result rpf_result;
struct pim_rpf old;
+ struct prefix nht_p;
+
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
+ pim_resolve_upstream_nh (&nht_p);
old.source_nexthop.interface = up->rpf.source_nexthop.interface;
old.source_nexthop.nbr = up->rpf.source_nexthop.nbr;
qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
++qpim_rpf_cache_refresh_events;
- pim_rp_setup ();
+ //It is called as part of pim_neighbor_add
+ //pim_rp_setup ();
return 0;
}
struct igmp_group *group;
struct prefix_sg sg;
int result;
+ int input_iface_vif_index = 0;
memset (&sg, 0, sizeof (struct prefix_sg));
sg.src = source->source_addr;
if (!source->source_channel_oil) {
struct in_addr vif_source;
struct pim_interface *pim_oif;
+ struct prefix nht_p, src, grp;
+ int ret = 0;
+ struct pim_nexthop_cache out_pnc;
+ struct pim_nexthop nexthop;
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);
+ /* Register addr with Zebra NHT */
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = vif_source;
+ memset (&out_pnc, 0, sizeof (struct pim_nexthop_cache));
+
+ if ((ret = pim_find_or_track_nexthop (&nht_p, NULL, NULL, &out_pnc)) == 1)
+ {
+ if (out_pnc.nexthop_num)
+ {
+ src.family = AF_INET;
+ src.prefixlen = IPV4_MAX_BITLEN;
+ src.u.prefix4 = vif_source; //RP or Src address
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = sg.grp;
+ memset (&nexthop, 0, sizeof (nexthop));
+ //Compute PIM RPF using Cached nexthop
+ pim_ecmp_nexthop_search (&out_pnc, &nexthop,
+ &src, &grp, 0);
+ if (nexthop.interface)
+ input_iface_vif_index = pim_if_find_vifindex_by_ifindex (nexthop.interface->ifindex);
+ }
+ else
+ {
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char buf1[INET_ADDRSTRLEN];
+ char buf2[INET_ADDRSTRLEN];
+ pim_inet4_dump("<source?>", nht_p.u.prefix4, buf1, sizeof(buf1));
+ pim_inet4_dump("<source?>", grp.u.prefix4, buf2, sizeof(buf2));
+ zlog_debug ("%s: NHT Nexthop not found for addr %s grp %s" ,
+ __PRETTY_FUNCTION__, buf1, buf2);
+ }
+ }
+ }
+ else
+ input_iface_vif_index = fib_lookup_if_vif_index(vif_source);
+
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char buf2[INET_ADDRSTRLEN];
+ pim_inet4_dump("<source?>", vif_source, buf2, sizeof(buf2));
+ zlog_debug ("%s: NHT %s vif_source %s vif_index:%d ", __PRETTY_FUNCTION__,
+ pim_str_sg_dump (&sg), buf2, input_iface_vif_index);
+ }
+
if (input_iface_vif_index < 1) {
if (PIM_DEBUG_IGMP_TRACE)
{
{
struct pim_upstream *up = ch->upstream;
uint32_t mask = PIM_OIF_FLAG_PROTO_PIM;
+ int input_iface_vif_index = 0;
if (PIM_DEBUG_PIM_TRACE) {
char source_str[INET_ADDRSTRLEN];
- char group_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
char upstream_str[INET_ADDRSTRLEN];
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)",
+ zlog_debug("%s: (S,G)=(%s,%s) oif=%s (%s)",
__PRETTY_FUNCTION__,
source_str, group_str, ch->interface->name, upstream_str);
}
- if (!up->channel_oil) {
- int input_iface_vif_index = fib_lookup_if_vif_index(up->upstream_addr);
- if (input_iface_vif_index < 1) {
- 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;
- }
+ /* Resolve IIF for upstream as mroute_del sets mfcc_parent to MAXVIFS,
+ as part of mroute_del called by pim_forward_stop.
+ */
+ if (!up->channel_oil ||
+ (up->channel_oil && up->channel_oil->oil.mfcc_parent >= MAXVIFS))
+ {
+ struct prefix nht_p, src, grp;
+ int ret = 0;
+ struct pim_nexthop_cache out_pnc;
+ struct pim_nexthop nexthop;
+
+ /* Register addr with Zebra NHT */
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = up->sg.grp;
+ memset (&out_pnc, 0, sizeof (struct pim_nexthop_cache));
+
+ if ((ret =
+ pim_find_or_track_nexthop (&nht_p, NULL, NULL, &out_pnc)) == 1)
+ {
+ if (out_pnc.nexthop_num)
+ {
+ src.family = AF_INET;
+ src.prefixlen = IPV4_MAX_BITLEN;
+ src.u.prefix4 = up->upstream_addr; //RP or Src address
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = up->sg.grp;
+ memset (&nexthop, 0, sizeof (nexthop));
+ //Compute PIM RPF using Cached nexthop
+ pim_ecmp_nexthop_search (&out_pnc, &nexthop, &src, &grp, 0);
+ input_iface_vif_index =
+ pim_if_find_vifindex_by_ifindex (nexthop.interface->ifindex);
+ }
+ else
+ {
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char buf1[INET_ADDRSTRLEN];
+ char buf2[INET_ADDRSTRLEN];
+ pim_inet4_dump("<source?>", nht_p.u.prefix4, buf1, sizeof(buf1));
+ pim_inet4_dump("<source?>", grp.u.prefix4, buf2, sizeof(buf2));
+ zlog_debug ("%s: NHT pnc is NULL for addr %s grp %s" ,
+ __PRETTY_FUNCTION__, buf1, buf2);
+ }
+ }
+ }
+ else
+ input_iface_vif_index = fib_lookup_if_vif_index (up->upstream_addr);
- up->channel_oil = pim_channel_oil_add(&up->sg,
- input_iface_vif_index);
- if (!up->channel_oil) {
- 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;
+ if (input_iface_vif_index < 1)
+ {
+ 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;
+ }
+ if (PIM_DEBUG_TRACE)
+ {
+ zlog_debug ("%s: NHT entry %s update channel_oil vif_index %d ",
+ __PRETTY_FUNCTION__, up->sg_str, input_iface_vif_index);
+ }
+ up->channel_oil = pim_channel_oil_add (&up->sg, input_iface_vif_index);
+ if (!up->channel_oil)
+ {
+ 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;
+ }
}
- }
if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
mask = PIM_OIF_FLAG_PROTO_IGMP;
- pim_channel_add_oif(up->channel_oil, ch->interface, mask);
+ pim_channel_add_oif (up->channel_oil, ch->interface, mask);
}
void pim_forward_stop(struct pim_ifchannel *ch)
for (i = 0; i < nexthop_num; ++i) {
enum nexthop_types_t nexthop_type;
struct pim_neighbor *nbr;
+ struct prefix p;
nexthop_type = stream_getc(s);
if (num_ifindex >= tab_size) {
break;
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);
+ stream_get (&nexthop_tab[num_ifindex].nexthop_addr.u.prefix6,
+ s,
+ sizeof(struct in6_addr));
nexthop_tab[num_ifindex].ifindex = stream_getl (s);
- nbr = pim_neighbor_find_if (if_lookup_by_index (nexthop_tab[num_ifindex].ifindex, VRF_DEFAULT));
+
+ p.family = AF_INET6;
+ p.prefixlen = IPV6_MAX_PREFIXLEN;
+ memcpy (&p.u.prefix6,
+ &nexthop_tab[num_ifindex].nexthop_addr.u.prefix6,
+ sizeof(struct in6_addr));
+
+ /*
+ * If we are sending v6 secondary assume we receive v6 secondary
+ */
+ if (pimg->send_v6_secondary)
+ nbr = pim_neighbor_find_by_secondary(if_lookup_by_index (nexthop_tab[num_ifindex].ifindex, VRF_DEFAULT), &p);
+ else
+ nbr = pim_neighbor_find_if (if_lookup_by_index (nexthop_tab[num_ifindex].ifindex, VRF_DEFAULT));
if (nbr)
{
nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET;
signed int qpim_rp_keep_alive_time = 0;
int64_t qpim_nexthop_lookups = 0;
int qpim_packet_process = PIM_DEFAULT_PACKET_PROCESS;
-struct pim_instance *pimg = NULL;
+uint8_t qpim_ecmp_enable = 0;
+uint8_t qpim_ecmp_rebalance_enable = 0;
+struct pim_instance *pimg = NULL;
int32_t qpim_register_suppress_time = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT;
int32_t qpim_register_probe_time = PIM_REGISTER_PROBE_TIME_DEFAULT;
* We will crash and burn otherwise
*/
exit(1);
- }
+ }
+
+ pimg->send_v6_secondary = 1;
+
}
return 0;
}
pim->vrf_id = vrf_id;
pim->afi = afi;
+ pim->spt_switchover = PIM_SPT_IMMEDIATE;
pim->rpf_hash = hash_create_size (256, pim_rpf_hash_key, pim_rpf_equal);
if (PIM_DEBUG_ZEBRA)
extern unsigned int qpim_keep_alive_time;
extern signed int qpim_rp_keep_alive_time;
extern int qpim_packet_process;
+extern uint8_t qpim_ecmp_enable;
+extern uint8_t qpim_ecmp_rebalance_enable;
+
#define PIM_DEFAULT_PACKET_PROCESS 3
#define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2)
#define PIM_DONT_DEBUG_MSDP_PACKETS (qpim_debugs &= ~PIM_MASK_MSDP_PACKETS)
#define PIM_DONT_DEBUG_MSDP_INTERNAL (qpim_debugs &= ~PIM_MASK_MSDP_INTERNAL)
+enum pim_spt_switchover {
+ PIM_SPT_IMMEDIATE,
+ PIM_SPT_INFINITY,
+};
+
/* Per VRF PIM DB */
struct pim_instance
{
afi_t afi;
vrf_id_t vrf_id;
+
+ enum pim_spt_switchover spt_switchover;
+
struct hash *rpf_hash;
+
void *ssm_info; /* per-vrf SSM configuration */
+
+ int send_v6_secondary;
};
extern struct pim_instance *pimg; //Pim Global Instance
for(i = 0; redist_type[i].str; i++)
{
- if (strncmp (redist_type[i].str, argv[2]->arg,
+ if (strncmp (redist_type[i].str, argv[1]->arg,
redist_type[i].str_min_len) == 0)
{
zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient,
}
}
- vty_out(vty, "Invalid type %s%s", argv[2]->arg,
+ vty_out(vty, "Invalid type %s%s", argv[1]->arg,
VTY_NEWLINE);
return CMD_WARNING;
for (i = 0; redist_type[i].str; i++)
{
- if (strncmp(redist_type[i].str, argv[3]->arg,
+ if (strncmp(redist_type[i].str, argv[2]->arg,
redist_type[i].str_min_len) == 0)
{
rip_metric_unset (redist_type[i].type, DONT_CARE_METRIC_RIP);
}
}
- vty_out(vty, "Invalid type %s%s", argv[3]->arg,
+ vty_out(vty, "Invalid type %s%s", argv[2]->arg,
VTY_NEWLINE);
return CMD_WARNING;
Connect the priviledged `network-control` plug to the snap:
- snap connect frr:network-control ubuntu-core:network-control
+ snap connect frr:network-control core:network-control
+See README.usage.md for more details on setting up and using the snap
+
DONE.
The Snap will be auto-started and running.
After installing the Snap, the priviledged plug need to be connected:
- snap connect frr:network-control ubuntu-core:network-control
+ snap connect frr:network-control core:network-control
Enabling/Disabling FRRouting Daemons
-------------------------------------------
options
- `frr.readme`:
Returns this document `cat README_usage.md`
+- `frr.set`:
+ Allows to enable `FPM` module. See FPM section below
and for debugging defined at this time (May get removed later - do not
depend on them). These are mainly intended to debug the Snap
- `frr.ldpd-debug`:
Starts ldpd daemon in foreground
+MPLS (LDP)
+----------
+The MPLS forwarding requires a Linux Kernel version 4.5 or newer and
+specific MPLS kernel modules loaded. It will be auto-detected by
+FRR. You can check the detected setup with the `show mpls status`
+command from within `frr.vtysh`
+
+The following kernel modules `mpls-router` and `mpls-iptunnel`
+need to be loaded. On Ubuntu 16.04, this can be done by editing
+'/etc/modules-load.d/modules.conf' and add the following lines:
+
+ # Load MPLS Kernel Modules
+ mpls-router
+ mpls-iptunnel
+
+For other distributions, please check the documentation on loading
+modules. You need to either reboot or use `modprobe` to manually load
+the modules as well before MPLS will be available.
+
+In addition to this, the MPLS Label-Processing needs to be enabled
+with `sysctl` on the required interfaces. Assuming the interfaces
+are named `eth0`, `eth1` and `eth2`, then the additional lines in
+`/etc/sysctl.conf` will enable it on a Ubuntu 16.04 system:
+
+ # Enable MPLS Label processing on all interfaces
+ net.mpls.conf.eth0.input=1
+ net.mpls.conf.eth1.input=1
+ net.mpls.conf.eth2.input=1
+ net.mpls.platform_labels=100000
+
+These settings require either a reboot or a manual configuration with
+`sysctl` as well.
+
+FPM Module
+----------
+The `frr.set` allows to turn FPM module on or off.
+
+ frr.set fpm {disable|protobuf|netlink}
+
+ Disables FPM or enables FPM with selected mode
+
+By default, the FPM module is disabled, but installed with netlink and
+protobuf support. To enable the FPM module, use the `frr.set fpm protobuf`
+or `frr.set fpm netlink` command. The command will only enable the mode
+for the next restart of zebra. Please reboot or restart zebra after
+changing the mode to become effective.
+
FAQ
---
- frr.vtysh displays `--MORE--` on long output. How to suppress this?
- Define `VTYSH_PAGER` to `cat` (default is `more`). (Ie add
`export VTYSH_PAGER=cat` to the end of your `.profile`)
+- ospfd / ospf6d are not running after installation
+ - Installing a new snap starts the daemons, but at this time they
+ may not have the required priviledged access. Make sure you
+ issue the `snap connect` command as given above (can be verified
+ with `snap interfaces`) and **THEN** restart the daemons (or
+ reboot the system).
+ This is a limitation of any snap package at this time which
+ requires priviledged interfaces (ie to manipulate routing tables)
+
Sourcecode available
====================
The source for this SNAP is available as part of the FRRouting
-Source Code Distribution.
+Source Code Distribution under `GPLv2 or later`
+
+<https://github.com/frrouting/frr.git>
+
+Instructions for rebuilding the snap are in `snapcraft/README.snap_build.md`
- https://github.com/frrouting/frr.git
+*Please checkout the desired branch before following the instructions
+as they may have changed between versions of FRR*
-Instructions for rebuilding the snap are in `README.snap_build.md`
+Official Webpage for FRR
+========================
+
+Official webpage for FRR is at <https://www.frrouting.org/>
Feedback welcome
================
Please send Feedback about this snap to Martin Winter at
`mwinter@opensourcerouting.org`
-
install -D -m 0755 isisd-service $(DESTDIR)/bin/
install -D -m 0755 pimd-service $(DESTDIR)/bin/
install -D -m 0755 ldpd-service $(DESTDIR)/bin/
-
+ install -D -m 0755 nhrpd-service $(DESTDIR)/bin/
+ install -D -m 0755 set-options $(DESTDIR)/bin/
--- /dev/null
+#!/bin/sh
+
+set -e -x
+
+if ! [ -e $SNAP_DATA/nhrpd.conf ]; then
+ cp $SNAP/etc/frr/nhrpd.conf.default $SNAP_DATA/nhrpd.conf
+fi
+exec $SNAP/sbin/nhrpd \
+ -f $SNAP_DATA/nhrpd.conf \
+ --pid_file $SNAP_DATA/nhrpd.pid \
+ --socket $SNAP_DATA/zsock \
+ --vty_socket $SNAP_DATA
--- /dev/null
+#!/bin/sh
+
+set -e
+
+case $1 in
+ fpm)
+ case $2 in
+ disable)
+ rm -f $SNAP_DATA/fpm.conf
+ echo "FPM module disabled. Please restart FRR"
+ ;;
+ protobuf)
+ echo "-M fpm:protobuf" > $SNAP_DATA/fpm.conf
+ echo "FPM enabled and set to protobuf mode. Please restart FRR"
+ ;;
+ netlink)
+ echo "-M fpm:netlink" > $SNAP_DATA/fpm.conf
+ echo "FPM enabled and set to netlink mode. Please restart FRR"
+ ;;
+ *)
+ echo "Usage:"
+ echo " ${SNAP_NAME}.set fpm {disable|protobuf|netlink}"
+ echo ""
+ echo " Disables FPM module or enables it with specified mode"
+ echo " Mode will be saved for next restart of zebra, but zebra"
+ echo " is not automatically restarted"
+ exit 1
+ ;;
+ esac
+ ;;
+ *)
+ echo "Usage:"
+ echo " ${SNAP_NAME}.set fpm {disable|protobuf|netlink}"
+ echo ""
+ echo " Disables FPM or enables FPM with selected mode"
+ exit 1
+ ;;
+esac
+
+exit 0
if ! [ -e $SNAP_DATA/vtysh.conf ]; then
cp $SNAP/etc/frr/vtysh.conf.default $SNAP_DATA/vtysh.conf
fi
+EXTRA_OPTIONS=""
+if [ -e $SNAP_DATA/fpm.conf ]; then
+ EXTRA_OPTIONS="`cat $SNAP_DATA/fpm.conf`"
+fi
exec $SNAP/sbin/zebra \
-f $SNAP_DATA/zebra.conf \
--pid_file $SNAP_DATA/zebra.pid \
--socket $SNAP_DATA/zsock \
- --vty_socket $SNAP_DATA
-
+ --vty_socket $SNAP_DATA \
+ --moduledir $SNAP/lib/frr/modules $EXTRA_OPTIONS
- network
- network-bind
- network-control
+ nhrpd:
+ command: bin/nhrpd-service
+ daemon: simple
+ plugs:
+ - network
+ - network-bind
+ - network-control
+ set:
+ command: bin/set-options
zebra-debug:
command: sbin/zebra -f $SNAP_DATA/zebra.conf --pid_file $SNAP_DATA/zebra.pid --socket $SNAP_DATA/zsock --vty_socket $SNAP_DATA
plugs:
- network-bind
- network-control
ldpd-debug:
- command: sbin/ldpd -f $SNAP_DATA/pimd.conf --pid_file $SNAP_DATA/pimd.pid --socket $SNAP_DATA/zsock --ctl_socket $SNAP_DATA --vty_socket $SNAP_DATA
+ command: sbin/ldpd -f $SNAP_DATA/ldpd.conf --pid_file $SNAP_DATA/ldpd.pid --socket $SNAP_DATA/zsock --ctl_socket $SNAP_DATA --vty_socket $SNAP_DATA
plugs:
- network
- network-bind
- network-control
-
+ nhrpd-debug:
+ command: sbin/nhrpd -f $SNAP_DATA/nhrpd.conf --pid_file $SNAP_DATA/nhrpd.pid --socket $SNAP_DATA/zsock --vty_socket $SNAP_DATA
+ plugs:
+ - network
+ - network-bind
+ - network-control
+
parts:
frr:
build-packages:
- gawk
- libreadline-dev
- texinfo
- - dejagnu
- libncurses5-dev
- texlive-latex-base
- texlive-generic-recommended
- chrpath
- pkg-config
- libjson-c-dev
+ - libc-ares-dev
+ - bison
+ - flex
+ - python3-dev
+ - protobuf-c-compiler
stage-packages:
- coreutils
- iproute2
- --enable-group=root
- --enable-pimd
- --enable-ldpd
+ - --enable-fpm
+ - --enable-protobuf
- --enable-configfile-mask=0640
- --enable-logfile-mask=0640
- --localstatedir=/var/run
ripd.conf.default: etc/frr/ripd.conf.default
ripngd.conf.default: etc/frr/ripngd.conf.default
ldpd.conf.default: etc/frr/ldpd.conf.default
+ nhrpd.conf.default: etc/frr/nhrpd.conf.default
vtysh.conf.default: etc/frr/vtysh.conf.default
frr-scripts:
plugin: make
"Layer2 VPN Address family\n"
"Ethernet Virtual Private Network Subsequent Address Family\n")
{
-#if defined(HAVE_EVPN)
vty->node = BGP_EVPN_NODE;
-#endif /* HAVE_EVPN */
return CMD_SUCCESS;
}
DEFUNSH (VTYSH_ALL,
vtysh_log_syslog,
vtysh_log_syslog_cmd,
- "log syslog <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>",
+ "log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
"Logging control\n"
"Set syslog logging level\n"
LOG_LEVEL_DESC)