mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 16:04:49 +00:00
Merge remote-tracking branch 'origin/master' into mpls2
This commit is contained in:
commit
c05f73e0f4
10
README
10
README
@ -1,13 +1,13 @@
|
|||||||
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.
|
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.
|
RIPv2, RIPng, PIM-SM/MSDP and LDP as well as very early support for IS-IS.
|
||||||
|
|
||||||
See the file REPORTING-BUGS to report bugs.
|
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
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
/* Ethernet-VPN Attribute handling file
|
/* Ethernet-VPN Attribute handling file
|
||||||
Copyright (C) 2016 6WIND
|
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
|
under the terms of the GNU General Public License as published by the
|
||||||
Free Software Foundation; either version 2, or (at your option) any
|
Free Software Foundation; either version 2, or (at your option) any
|
||||||
later version.
|
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
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
General Public License for more details.
|
General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
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
|
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
02111-1307, USA. */
|
02111-1307, USA. */
|
||||||
|
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
/* E-VPN attribute handling structure file
|
/* E-VPN attribute handling structure file
|
||||||
Copyright (C) 2016 6WIND
|
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
|
under the terms of the GNU General Public License as published by the
|
||||||
Free Software Foundation; either version 2, or (at your option) any
|
Free Software Foundation; either version 2, or (at your option) any
|
||||||
later version.
|
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
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
General Public License for more details.
|
General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
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
|
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
02111-1307, USA. */
|
02111-1307, USA. */
|
||||||
|
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
/* Ethernet-VPN Packet and vty Processing File
|
/* Ethernet-VPN Packet and vty Processing File
|
||||||
Copyright (C) 2016 6WIND
|
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
|
under the terms of the GNU General Public License as published by the
|
||||||
Free Software Foundation; either version 2, or (at your option) any
|
Free Software Foundation; either version 2, or (at your option) any
|
||||||
later version.
|
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
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
General Public License for more details.
|
General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
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
|
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
02111-1307, USA. */
|
02111-1307, USA. */
|
||||||
|
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
/* E-VPN header for packet handling
|
/* E-VPN header for packet handling
|
||||||
Copyright (C) 2016 6WIND
|
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
|
under the terms of the GNU General Public License as published by the
|
||||||
Free Software Foundation; either version 2, or (at your option) any
|
Free Software Foundation; either version 2, or (at your option) any
|
||||||
later version.
|
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
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
General Public License for more details.
|
General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
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
|
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
02111-1307, USA. */
|
02111-1307, USA. */
|
||||||
|
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
/* Ethernet-VPN Packet and vty Processing File
|
/* Ethernet-VPN Packet and vty Processing File
|
||||||
Copyright (C) 2017 6WIND
|
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
|
under the terms of the GNU General Public License as published by the
|
||||||
Free Software Foundation; either version 2, or (at your option) any
|
Free Software Foundation; either version 2, or (at your option) any
|
||||||
later version.
|
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
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
General Public License for more details.
|
General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
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
|
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
02111-1307, USA. */
|
02111-1307, USA. */
|
||||||
|
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
/* EVPN VTY functions to EVPN
|
/* EVPN VTY functions to EVPN
|
||||||
Copyright (C) 2017 6WIND
|
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
|
under the terms of the GNU General Public License as published by the
|
||||||
Free Software Foundation; either version 2, or (at your option) any
|
Free Software Foundation; either version 2, or (at your option) any
|
||||||
later version.
|
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
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
General Public License for more details.
|
General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
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
|
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
02111-1307, USA. */
|
02111-1307, USA. */
|
||||||
|
|
||||||
|
@ -66,6 +66,7 @@ static const struct option longopts[] =
|
|||||||
{ "listenon", required_argument, NULL, 'l'},
|
{ "listenon", required_argument, NULL, 'l'},
|
||||||
{ "retain", no_argument, NULL, 'r'},
|
{ "retain", no_argument, NULL, 'r'},
|
||||||
{ "no_kernel", no_argument, NULL, 'n'},
|
{ "no_kernel", no_argument, NULL, 'n'},
|
||||||
|
{ "skip_runas", no_argument, NULL, 'S'},
|
||||||
{ "ecmp", required_argument, NULL, 'e'},
|
{ "ecmp", required_argument, NULL, 'e'},
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
@ -151,7 +152,8 @@ sigint (void)
|
|||||||
if (! retain_mode)
|
if (! retain_mode)
|
||||||
{
|
{
|
||||||
bgp_terminate ();
|
bgp_terminate ();
|
||||||
zprivs_terminate (&bgpd_privs);
|
if (bgpd_privs.user) /* NULL if skip_runas flag set */
|
||||||
|
zprivs_terminate (&bgpd_privs);
|
||||||
}
|
}
|
||||||
|
|
||||||
bgp_exit (0);
|
bgp_exit (0);
|
||||||
@ -365,6 +367,8 @@ main (int argc, char **argv)
|
|||||||
|
|
||||||
int bgp_port = BGP_PORT_DEFAULT;
|
int bgp_port = BGP_PORT_DEFAULT;
|
||||||
char *bgp_address = NULL;
|
char *bgp_address = NULL;
|
||||||
|
int no_fib_flag = 0;
|
||||||
|
int skip_runas = 0;
|
||||||
|
|
||||||
frr_preinit(&bgpd_di, argc, argv);
|
frr_preinit(&bgpd_di, argc, argv);
|
||||||
frr_opt_add("p:l:rne:", longopts,
|
frr_opt_add("p:l:rne:", longopts,
|
||||||
@ -372,6 +376,7 @@ main (int argc, char **argv)
|
|||||||
" -l, --listenon Listen on specified address (implies -n)\n"
|
" -l, --listenon Listen on specified address (implies -n)\n"
|
||||||
" -r, --retain When program terminates, retain added route by bgpd.\n"
|
" -r, --retain When program terminates, retain added route by bgpd.\n"
|
||||||
" -n, --no_kernel Do not install route to kernel.\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");
|
" -e, --ecmp Specify ECMP to use.\n");
|
||||||
|
|
||||||
/* Command line argument treatment. */
|
/* Command line argument treatment. */
|
||||||
@ -391,7 +396,7 @@ main (int argc, char **argv)
|
|||||||
if (tmp_port <= 0 || tmp_port > 0xffff)
|
if (tmp_port <= 0 || tmp_port > 0xffff)
|
||||||
bgp_port = BGP_PORT_DEFAULT;
|
bgp_port = BGP_PORT_DEFAULT;
|
||||||
else
|
else
|
||||||
bm->port = tmp_port;
|
bgp_port = tmp_port;
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
multipath_num = atoi (optarg);
|
multipath_num = atoi (optarg);
|
||||||
@ -408,18 +413,25 @@ main (int argc, char **argv)
|
|||||||
bgp_address = optarg;
|
bgp_address = optarg;
|
||||||
/* listenon implies -n */
|
/* listenon implies -n */
|
||||||
case 'n':
|
case 'n':
|
||||||
bgp_option_set (BGP_OPT_NO_FIB);
|
no_fib_flag = 1;
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
skip_runas = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
frr_help_exit (1);
|
frr_help_exit (1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (skip_runas)
|
||||||
|
memset (&bgpd_privs, 0, sizeof (bgpd_privs));
|
||||||
|
|
||||||
/* BGP master init. */
|
/* BGP master init. */
|
||||||
bgp_master_init (frr_init ());
|
bgp_master_init (frr_init ());
|
||||||
bm->port = bgp_port;
|
bm->port = bgp_port;
|
||||||
bm->address = bgp_address;
|
bm->address = bgp_address;
|
||||||
|
if (no_fib_flag)
|
||||||
|
bgp_option_set (BGP_OPT_NO_FIB);
|
||||||
|
|
||||||
/* Initializations. */
|
/* Initializations. */
|
||||||
bgp_vrf_init ();
|
bgp_vrf_init ();
|
||||||
|
@ -8424,7 +8424,7 @@ bgp_show_lcommunity (struct vty *vty, struct bgp *bgp, int argc,
|
|||||||
buffer_putc (b, ' ');
|
buffer_putc (b, ' ');
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (strmatch (argv[i]->text, "<AA:BB:CC>"))
|
if (strmatch (argv[i]->text, "AA:BB:CC"))
|
||||||
{
|
{
|
||||||
first = 1;
|
first = 1;
|
||||||
buffer_putstr (b, argv[i]->arg);
|
buffer_putstr (b, argv[i]->arg);
|
||||||
@ -8440,7 +8440,7 @@ bgp_show_lcommunity (struct vty *vty, struct bgp *bgp, int argc,
|
|||||||
XFREE (MTYPE_TMP, str);
|
XFREE (MTYPE_TMP, str);
|
||||||
if (! lcom)
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8554,8 +8554,7 @@ DEFUN (show_ip_bgp_large_community,
|
|||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
argv_find (argv, argc, "large-community", &idx);
|
if (argv_find (argv, argc, "AA:BB:CC", &idx))
|
||||||
if (strmatch(argv[idx+1]->text, "AA:BB:CC"))
|
|
||||||
return bgp_show_lcommunity (vty, bgp, argc, argv, afi, safi, uj);
|
return bgp_show_lcommunity (vty, bgp, argc, argv, afi, safi, uj);
|
||||||
else
|
else
|
||||||
return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_all, NULL, uj);
|
return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_all, NULL, uj);
|
||||||
@ -8818,8 +8817,6 @@ static int
|
|||||||
bgp_show_regexp (struct vty *vty, const char *regstr, afi_t afi,
|
bgp_show_regexp (struct vty *vty, const char *regstr, afi_t afi,
|
||||||
safi_t safi, enum bgp_show_type type)
|
safi_t safi, enum bgp_show_type type)
|
||||||
{
|
{
|
||||||
return CMD_SUCCESS;
|
|
||||||
|
|
||||||
regex_t *regex;
|
regex_t *regex;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
@ -1437,7 +1437,7 @@ route_set_aspath_prepend_compile (const char *arg)
|
|||||||
{
|
{
|
||||||
unsigned int num;
|
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 (void*)(uintptr_t)num;
|
||||||
|
|
||||||
return route_aspath_compile(arg);
|
return route_aspath_compile(arg);
|
||||||
@ -3677,12 +3677,12 @@ DEFUN (set_aspath_prepend_asn,
|
|||||||
|
|
||||||
DEFUN (set_aspath_prepend_lastas,
|
DEFUN (set_aspath_prepend_lastas,
|
||||||
set_aspath_prepend_lastas_cmd,
|
set_aspath_prepend_lastas_cmd,
|
||||||
"set as-path prepend last-as (1-9)",
|
"set as-path prepend last-as (1-10)",
|
||||||
SET_STR
|
SET_STR
|
||||||
"Transform BGP AS_PATH attribute\n"
|
"Transform BGP AS_PATH attribute\n"
|
||||||
"Prepend to the as-path\n"
|
"Prepend to the as-path\n"
|
||||||
"Use the peer's AS-number\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);
|
return set_aspath_prepend_asn (self, vty, argc, argv);
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
/* VPN Related functions
|
/* VPN Related functions
|
||||||
Copyright (C) 2017 6WIND
|
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
|
under the terms of the GNU General Public License as published by the
|
||||||
Free Software Foundation; either version 2, or (at your option) any
|
Free Software Foundation; either version 2, or (at your option) any
|
||||||
later version.
|
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
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
General Public License for more details.
|
General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
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
|
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
02111-1307, USA. */
|
02111-1307, USA. */
|
||||||
|
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
/* VPN common functions to MP-BGP
|
/* VPN common functions to MP-BGP
|
||||||
Copyright (C) 2017 6WIND
|
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
|
under the terms of the GNU General Public License as published by the
|
||||||
Free Software Foundation; either version 2, or (at your option) any
|
Free Software Foundation; either version 2, or (at your option) any
|
||||||
later version.
|
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
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
General Public License for more details.
|
General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
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
|
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
02111-1307, USA. */
|
02111-1307, USA. */
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
##
|
##
|
||||||
AC_PREREQ(2.60)
|
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_URL="https://frrouting.org/"
|
||||||
PACKAGE_FULLNAME="FRRouting"
|
PACKAGE_FULLNAME="FRRouting"
|
||||||
AC_SUBST(PACKAGE_FULLNAME)
|
AC_SUBST(PACKAGE_FULLNAME)
|
||||||
|
27
debian/changelog
vendored
27
debian/changelog
vendored
@ -1,3 +1,30 @@
|
|||||||
|
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
|
frr (2.1) Released; urgency=medium
|
||||||
|
|
||||||
* Switchover to FRR
|
* Switchover to FRR
|
||||||
|
@ -218,18 +218,14 @@ routing utility. It contains @command{ifconfig}, @command{route},
|
|||||||
|
|
||||||
After configuring the software, you will need to compile it for your
|
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
|
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
|
directory and the software will be compiled. Cliff Note versions of
|
||||||
at this stage, be certain to send a bug report @xref{Bug Reports}.
|
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
|
@example
|
||||||
% ./configure
|
% ./bootstrap.sh
|
||||||
.
|
% ./configure <appropriate to your system>
|
||||||
.
|
|
||||||
.
|
|
||||||
./configure output
|
|
||||||
.
|
|
||||||
.
|
|
||||||
.
|
|
||||||
% make
|
% make
|
||||||
@end example
|
@end example
|
||||||
@c A - End of node, Building the Software
|
@c A - End of node, Building the Software
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
/* ignore harmless bug in old versions of flex */
|
||||||
|
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||||
|
|
||||||
#include "command_parse.h"
|
#include "command_parse.h"
|
||||||
|
|
||||||
#define YY_USER_ACTION yylloc->last_column += yyleng;
|
#define YY_USER_ACTION yylloc->last_column += yyleng;
|
||||||
|
@ -254,6 +254,7 @@ DEFUN (distribute_list,
|
|||||||
distribute_list_cmd,
|
distribute_list_cmd,
|
||||||
"distribute-list [prefix] WORD <in|out> [WORD]",
|
"distribute-list [prefix] WORD <in|out> [WORD]",
|
||||||
"Filter networks in routing updates\n"
|
"Filter networks in routing updates\n"
|
||||||
|
"Specify a prefix\n"
|
||||||
"Access-list name\n"
|
"Access-list name\n"
|
||||||
"Filter incoming routing updates\n"
|
"Filter incoming routing updates\n"
|
||||||
"Filter outgoing routing updates\n"
|
"Filter outgoing routing updates\n"
|
||||||
@ -316,7 +317,9 @@ DEFUN (no_distribute_list,
|
|||||||
no_distribute_list_cmd,
|
no_distribute_list_cmd,
|
||||||
"no [ipv6] distribute-list [prefix] WORD <in|out> [WORD]",
|
"no [ipv6] distribute-list [prefix] WORD <in|out> [WORD]",
|
||||||
NO_STR
|
NO_STR
|
||||||
|
"IPv6\n"
|
||||||
"Filter networks in routing updates\n"
|
"Filter networks in routing updates\n"
|
||||||
|
"Specify a prefix\n"
|
||||||
"Access-list name\n"
|
"Access-list name\n"
|
||||||
"Filter incoming routing updates\n"
|
"Filter incoming routing updates\n"
|
||||||
"Filter outgoing routing updates\n"
|
"Filter outgoing routing updates\n"
|
||||||
|
@ -188,3 +188,11 @@ pqueue_remove_at (int index, struct pqueue *queue)
|
|||||||
trickle_down (index, queue);
|
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);
|
||||||
|
}
|
||||||
|
@ -39,6 +39,7 @@ extern void pqueue_delete (struct pqueue *queue);
|
|||||||
extern void pqueue_enqueue (void *data, struct pqueue *queue);
|
extern void pqueue_enqueue (void *data, struct pqueue *queue);
|
||||||
extern void *pqueue_dequeue (struct pqueue *queue);
|
extern void *pqueue_dequeue (struct pqueue *queue);
|
||||||
extern void pqueue_remove_at (int index, 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_down (int index, struct pqueue *queue);
|
||||||
extern void trickle_up (int index, struct pqueue *queue);
|
extern void trickle_up (int index, struct pqueue *queue);
|
||||||
|
@ -769,6 +769,7 @@ zprivs_init(struct zebra_privs_t *zprivs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
zprivs_state.zsuid = geteuid(); /* initial uid */
|
||||||
/* add groups only if we changed uid - otherwise skip */
|
/* add groups only if we changed uid - otherwise skip */
|
||||||
if ((ngroups) && (zprivs_state.zsuid != zprivs_state.zuid))
|
if ((ngroups) && (zprivs_state.zsuid != zprivs_state.zuid))
|
||||||
{
|
{
|
||||||
|
@ -1531,7 +1531,9 @@ lm_label_manager_connect (struct zclient *zclient)
|
|||||||
vrf_id_t vrf_id;
|
vrf_id_t vrf_id;
|
||||||
u_int16_t cmd;
|
u_int16_t cmd;
|
||||||
|
|
||||||
zlog_debug ("Connecting to Label Manager");
|
if (zclient_debug)
|
||||||
|
zlog_debug ("Connecting to Label Manager");
|
||||||
|
|
||||||
if (zclient->sock < 0)
|
if (zclient->sock < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -1563,7 +1565,8 @@ lm_label_manager_connect (struct zclient *zclient)
|
|||||||
zclient->sock = -1;
|
zclient->sock = -1;
|
||||||
return -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 */
|
/* read response */
|
||||||
s = zclient->ibuf;
|
s = zclient->ibuf;
|
||||||
@ -1577,8 +1580,9 @@ lm_label_manager_connect (struct zclient *zclient)
|
|||||||
}
|
}
|
||||||
/* result */
|
/* result */
|
||||||
result = stream_getc(s);
|
result = stream_getc(s);
|
||||||
zlog_debug ("%s: Label Manager connect response (%d bytes) received, result %u",
|
if (zclient_debug)
|
||||||
__func__, size, result);
|
zlog_debug ("%s: Label Manager connect response (%d bytes) received, result %u",
|
||||||
|
__func__, size, result);
|
||||||
|
|
||||||
return (int)result;
|
return (int)result;
|
||||||
}
|
}
|
||||||
@ -1609,7 +1613,9 @@ lm_get_label_chunk (struct zclient *zclient, u_char keep, uint32_t chunk_size,
|
|||||||
u_int16_t cmd;
|
u_int16_t cmd;
|
||||||
u_char response_keep;
|
u_char response_keep;
|
||||||
|
|
||||||
zlog_debug ("Getting Label Chunk");
|
if (zclient_debug)
|
||||||
|
zlog_debug ("Getting Label Chunk");
|
||||||
|
|
||||||
if (zclient->sock < 0)
|
if (zclient->sock < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -1639,7 +1645,8 @@ lm_get_label_chunk (struct zclient *zclient, u_char keep, uint32_t chunk_size,
|
|||||||
zclient->sock = -1;
|
zclient->sock = -1;
|
||||||
return -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 */
|
/* read response */
|
||||||
s = zclient->ibuf;
|
s = zclient->ibuf;
|
||||||
@ -1651,7 +1658,9 @@ lm_get_label_chunk (struct zclient *zclient, u_char keep, uint32_t chunk_size,
|
|||||||
zlog_err ("%s: Invalid Get Label Chunk Message Reply Header", __func__);
|
zlog_err ("%s: Invalid Get Label Chunk Message Reply Header", __func__);
|
||||||
return -1;
|
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 */
|
/* keep */
|
||||||
response_keep = stream_getc(s);
|
response_keep = stream_getc(s);
|
||||||
/* start and end labels */
|
/* start and end labels */
|
||||||
@ -1672,8 +1681,9 @@ lm_get_label_chunk (struct zclient *zclient, u_char keep, uint32_t chunk_size,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
zlog_debug ("Label Chunk assign: %u - %u (%u) ",
|
if (zclient_debug)
|
||||||
*start, *end, response_keep);
|
zlog_debug ("Label Chunk assign: %u - %u (%u) ",
|
||||||
|
*start, *end, response_keep);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1692,7 +1702,9 @@ lm_release_label_chunk (struct zclient *zclient, uint32_t start, uint32_t end)
|
|||||||
int ret;
|
int ret;
|
||||||
struct stream *s;
|
struct stream *s;
|
||||||
|
|
||||||
zlog_debug ("Releasing Label Chunk");
|
if (zclient_debug)
|
||||||
|
zlog_debug ("Releasing Label Chunk");
|
||||||
|
|
||||||
if (zclient->sock < 0)
|
if (zclient->sock < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -3557,7 +3557,7 @@ show_ip_ospf_interface_common (struct vty *vty, struct ospf *ospf, int argc,
|
|||||||
VTY_NEWLINE, VTY_NEWLINE);
|
VTY_NEWLINE, VTY_NEWLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc == (iface_argv + 1))
|
if (argc == iface_argv)
|
||||||
{
|
{
|
||||||
/* Show All Interfaces.*/
|
/* Show All Interfaces.*/
|
||||||
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
|
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
|
||||||
@ -3570,25 +3570,6 @@ show_ip_ospf_interface_common (struct vty *vty, struct ospf *ospf, int argc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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
|
else
|
||||||
{
|
{
|
||||||
/* Interface name is specified. */
|
/* Interface name is specified. */
|
||||||
@ -3634,7 +3615,10 @@ DEFUN (show_ip_ospf_interface,
|
|||||||
if ((ospf = ospf_lookup()) == NULL || !ospf->oi_running)
|
if ((ospf = ospf_lookup()) == NULL || !ospf->oi_running)
|
||||||
return CMD_SUCCESS;
|
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,
|
DEFUN (show_ip_ospf_instance_interface,
|
||||||
@ -3657,7 +3641,10 @@ DEFUN (show_ip_ospf_instance_interface,
|
|||||||
if ((ospf = ospf_lookup_instance (instance)) == NULL || !ospf->oi_running)
|
if ((ospf = ospf_lookup_instance (instance)) == NULL || !ospf->oi_running)
|
||||||
return CMD_SUCCESS;
|
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
|
static void
|
||||||
|
326
pimd/pim_cmd.c
326
pimd/pim_cmd.c
@ -26,6 +26,8 @@
|
|||||||
#include "prefix.h"
|
#include "prefix.h"
|
||||||
#include "zclient.h"
|
#include "zclient.h"
|
||||||
#include "plist.h"
|
#include "plist.h"
|
||||||
|
#include "hash.h"
|
||||||
|
#include "nexthop.h"
|
||||||
|
|
||||||
#include "pimd.h"
|
#include "pimd.h"
|
||||||
#include "pim_mroute.h"
|
#include "pim_mroute.h"
|
||||||
@ -55,6 +57,7 @@
|
|||||||
#include "pim_zlookup.h"
|
#include "pim_zlookup.h"
|
||||||
#include "pim_msdp.h"
|
#include "pim_msdp.h"
|
||||||
#include "pim_ssm.h"
|
#include "pim_ssm.h"
|
||||||
|
#include "pim_nht.h"
|
||||||
|
|
||||||
static struct cmd_node pim_global_node = {
|
static struct cmd_node pim_global_node = {
|
||||||
PIM_NODE,
|
PIM_NODE,
|
||||||
@ -817,6 +820,7 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, u_ch
|
|||||||
mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd);
|
mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd);
|
||||||
|
|
||||||
if (uj) {
|
if (uj) {
|
||||||
|
char pbuf[PREFIX2STR_BUFFER];
|
||||||
json_row = json_object_new_object();
|
json_row = json_object_new_object();
|
||||||
json_object_pim_ifp_add(json_row, ifp);
|
json_object_pim_ifp_add(json_row, ifp);
|
||||||
|
|
||||||
@ -828,7 +832,10 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, u_ch
|
|||||||
|
|
||||||
sec_list = json_object_new_array();
|
sec_list = json_object_new_array();
|
||||||
for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, sec_node, sec_addr)) {
|
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);
|
json_object_object_add(json_row, "secondaryAddressList", sec_list);
|
||||||
}
|
}
|
||||||
@ -919,11 +926,14 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, u_ch
|
|||||||
vty_out(vty, "Use Source : %s%s", inet_ntoa(pim_ifp->update_source), VTY_NEWLINE);
|
vty_out(vty, "Use Source : %s%s", inet_ntoa(pim_ifp->update_source), VTY_NEWLINE);
|
||||||
}
|
}
|
||||||
if (pim_ifp->sec_addr_list) {
|
if (pim_ifp->sec_addr_list) {
|
||||||
|
char pbuf[PREFIX2STR_BUFFER];
|
||||||
vty_out(vty, "Address : %s (primary)%s",
|
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)) {
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, sec_node, sec_addr)) {
|
||||||
vty_out(vty, " %s%s",
|
vty_out(vty, " %s%s",
|
||||||
inet_ntoa(sec_addr->addr), VTY_NEWLINE);
|
prefix2str(&sec_addr->addr,
|
||||||
|
pbuf,
|
||||||
|
sizeof(pbuf)), VTY_NEWLINE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
vty_out(vty, "Address : %s%s", inet_ntoa(ifaddr), VTY_NEWLINE);
|
vty_out(vty, "Address : %s%s", inet_ntoa(ifaddr), VTY_NEWLINE);
|
||||||
@ -1040,6 +1050,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj)
|
|||||||
struct pim_upstream *up;
|
struct pim_upstream *up;
|
||||||
int fhr = 0;
|
int fhr = 0;
|
||||||
int pim_nbrs = 0;
|
int pim_nbrs = 0;
|
||||||
|
int pim_ifchannels = 0;
|
||||||
json_object *json = NULL;
|
json_object *json = NULL;
|
||||||
json_object *json_row = NULL;
|
json_object *json_row = NULL;
|
||||||
json_object *json_tmp;
|
json_object *json_tmp;
|
||||||
@ -1056,6 +1067,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
pim_nbrs = pim_ifp->pim_neighbor_list->count;
|
pim_nbrs = pim_ifp->pim_neighbor_list->count;
|
||||||
|
pim_ifchannels = pim_ifp->pim_ifchannel_list->count;
|
||||||
fhr = 0;
|
fhr = 0;
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode, up))
|
for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode, up))
|
||||||
@ -1066,6 +1078,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj)
|
|||||||
json_row = json_object_new_object();
|
json_row = json_object_new_object();
|
||||||
json_object_pim_ifp_add(json_row, ifp);
|
json_object_pim_ifp_add(json_row, ifp);
|
||||||
json_object_int_add(json_row, "pimNeighbors", pim_nbrs);
|
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_int_add(json_row, "firstHopRouter", fhr);
|
||||||
json_object_string_add(json_row, "pimDesignatedRouter", inet_ntoa(pim_ifp->pim_dr_addr));
|
json_object_string_add(json_row, "pimDesignatedRouter", inet_ntoa(pim_ifp->pim_dr_addr));
|
||||||
|
|
||||||
@ -1078,7 +1091,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj)
|
|||||||
if (uj) {
|
if (uj) {
|
||||||
vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
|
vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
|
||||||
} else {
|
} 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) {
|
json_object_object_foreach(json, key, val) {
|
||||||
vty_out(vty, "%-9s ", key);
|
vty_out(vty, "%-9s ", key);
|
||||||
@ -1100,7 +1113,10 @@ static void pim_show_interfaces(struct vty *vty, u_char uj)
|
|||||||
}
|
}
|
||||||
|
|
||||||
json_object_object_get_ex(val, "firstHopRouter", &json_tmp);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1608,13 +1624,9 @@ static void pim_show_neighbors_secondary(struct vty *vty)
|
|||||||
neigh_src_str, sizeof(neigh_src_str));
|
neigh_src_str, sizeof(neigh_src_str));
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, prefix_node, p)) {
|
for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, prefix_node, p)) {
|
||||||
char neigh_sec_str[INET_ADDRSTRLEN];
|
char neigh_sec_str[PREFIX2STR_BUFFER];
|
||||||
|
|
||||||
if (p->family != AF_INET)
|
prefix2str(p, neigh_sec_str, sizeof(neigh_sec_str));
|
||||||
continue;
|
|
||||||
|
|
||||||
pim_inet4_dump("<src?>", p->u.prefix4,
|
|
||||||
neigh_sec_str, sizeof(neigh_sec_str));
|
|
||||||
|
|
||||||
vty_out(vty, "%-9s %-15s %-15s %-15s%s",
|
vty_out(vty, "%-9s %-15s %-15s %-15s%s",
|
||||||
ifp->name,
|
ifp->name,
|
||||||
@ -2059,6 +2071,50 @@ static void pim_show_rpf(struct vty *vty, u_char uj)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
static void igmp_show_groups(struct vty *vty, u_char uj)
|
||||||
{
|
{
|
||||||
struct listnode *ifnode;
|
struct listnode *ifnode;
|
||||||
@ -2793,6 +2849,99 @@ DEFUN (show_ip_pim_rpf,
|
|||||||
return CMD_SUCCESS;
|
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)
|
static void show_multicast_interfaces(struct vty *vty)
|
||||||
{
|
{
|
||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
@ -2871,15 +3020,17 @@ DEFUN (show_ip_multicast,
|
|||||||
PIM_MAX_USABLE_VIFS,
|
PIM_MAX_USABLE_VIFS,
|
||||||
VTY_NEWLINE);
|
VTY_NEWLINE);
|
||||||
|
|
||||||
vty_out(vty, "%s", VTY_NEWLINE);
|
vty_out (vty, "%s", VTY_NEWLINE);
|
||||||
vty_out(vty, "Upstream Join Timer: %d secs%s",
|
vty_out (vty, "Upstream Join Timer: %d secs%s",
|
||||||
qpim_t_periodic,
|
qpim_t_periodic, VTY_NEWLINE);
|
||||||
VTY_NEWLINE);
|
vty_out (vty, "Join/Prune Holdtime: %d secs%s",
|
||||||
vty_out(vty, "Join/Prune Holdtime: %d secs%s",
|
PIM_JP_HOLDTIME, VTY_NEWLINE);
|
||||||
PIM_JP_HOLDTIME,
|
vty_out (vty, "PIM ECMP: %s%s",
|
||||||
VTY_NEWLINE);
|
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);
|
show_rpf_refresh_stats(vty, now, NULL);
|
||||||
|
|
||||||
@ -3410,6 +3561,35 @@ pim_rp_cmd_worker (struct vty *vty, const char *rp, const char *group, const cha
|
|||||||
return CMD_SUCCESS;
|
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,
|
DEFUN (ip_pim_joinprune_time,
|
||||||
ip_pim_joinprune_time_cmd,
|
ip_pim_joinprune_time_cmd,
|
||||||
"ip pim join-prune-interval <60-600>",
|
"ip pim join-prune-interval <60-600>",
|
||||||
@ -3510,6 +3690,31 @@ DEFUN (no_ip_pim_packets,
|
|||||||
return CMD_SUCCESS;
|
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,
|
DEFUN (ip_pim_rp,
|
||||||
ip_pim_rp_cmd,
|
ip_pim_rp_cmd,
|
||||||
"ip pim rp A.B.C.D [A.B.C.D/M]",
|
"ip pim rp A.B.C.D [A.B.C.D/M]",
|
||||||
@ -3577,10 +3782,10 @@ DEFUN (no_ip_pim_rp,
|
|||||||
"ip address of RP\n"
|
"ip address of RP\n"
|
||||||
"Group Address range to cover\n")
|
"Group Address range to cover\n")
|
||||||
{
|
{
|
||||||
int idx_ipv4 = 4;
|
int idx_ipv4 = 4, idx_group = 0;
|
||||||
|
|
||||||
if (argc == (idx_ipv4 + 1))
|
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_ipv4 + 1]->arg, NULL);
|
return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, argv[idx_group]->arg, NULL);
|
||||||
else
|
else
|
||||||
return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, NULL, NULL);
|
return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, NULL, NULL);
|
||||||
}
|
}
|
||||||
@ -3826,6 +4031,58 @@ DEFUN (no_ip_ssmpingd,
|
|||||||
return CMD_SUCCESS;
|
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
|
static int
|
||||||
pim_cmd_igmp_start (struct vty *vty, struct interface *ifp)
|
pim_cmd_igmp_start (struct vty *vty, struct interface *ifp)
|
||||||
{
|
{
|
||||||
@ -6149,13 +6406,16 @@ DEFUN (show_ip_msdp_sa_sg,
|
|||||||
"JavaScript Object Notation\n")
|
"JavaScript Object Notation\n")
|
||||||
{
|
{
|
||||||
u_char uj = use_json(argc, argv);
|
u_char uj = use_json(argc, argv);
|
||||||
if (uj)
|
|
||||||
argc--;
|
|
||||||
|
|
||||||
if (argc == 5)
|
int idx = 0;
|
||||||
ip_msdp_show_sa_sg(vty, argv[4]->arg, argv[5]->arg, uj);
|
char *src_ip = argv_find (argv, argc, "A.B.C.D", &idx) ? argv[idx++]->arg : NULL;
|
||||||
else if (argc == 4)
|
char *grp_ip = idx < argc && argv_find (argv, argc, "A.B.C.D", &idx) ?
|
||||||
ip_msdp_show_sa_addr(vty, argv[4]->arg, uj);
|
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
|
else
|
||||||
ip_msdp_show_sa(vty, uj);
|
ip_msdp_show_sa(vty, uj);
|
||||||
|
|
||||||
@ -6181,16 +6441,24 @@ void pim_cmd_init()
|
|||||||
install_element (CONFIG_NODE, &ip_pim_ssm_prefix_list_cmd);
|
install_element (CONFIG_NODE, &ip_pim_ssm_prefix_list_cmd);
|
||||||
install_element (CONFIG_NODE, &ip_pim_register_suppress_cmd);
|
install_element (CONFIG_NODE, &ip_pim_register_suppress_cmd);
|
||||||
install_element (CONFIG_NODE, &no_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, &ip_pim_joinprune_time_cmd);
|
||||||
install_element (CONFIG_NODE, &no_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, &ip_pim_keep_alive_cmd);
|
||||||
install_element (CONFIG_NODE, &no_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, &ip_pim_packets_cmd);
|
||||||
install_element (CONFIG_NODE, &no_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, &ip_ssmpingd_cmd);
|
||||||
install_element (CONFIG_NODE, &no_ip_ssmpingd_cmd);
|
install_element (CONFIG_NODE, &no_ip_ssmpingd_cmd);
|
||||||
install_element (CONFIG_NODE, &ip_msdp_peer_cmd);
|
install_element (CONFIG_NODE, &ip_msdp_peer_cmd);
|
||||||
install_element (CONFIG_NODE, &no_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_ip_igmp_cmd);
|
||||||
install_element (INTERFACE_NODE, &interface_no_ip_igmp_cmd);
|
install_element (INTERFACE_NODE, &interface_no_ip_igmp_cmd);
|
||||||
@ -6246,6 +6514,8 @@ void pim_cmd_init()
|
|||||||
install_element (VIEW_NODE, &show_ip_rib_cmd);
|
install_element (VIEW_NODE, &show_ip_rib_cmd);
|
||||||
install_element (VIEW_NODE, &show_ip_ssmpingd_cmd);
|
install_element (VIEW_NODE, &show_ip_ssmpingd_cmd);
|
||||||
install_element (VIEW_NODE, &show_debugging_pim_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_interfaces_cmd);
|
||||||
install_element (ENABLE_NODE, &clear_ip_igmp_interfaces_cmd);
|
install_element (ENABLE_NODE, &clear_ip_igmp_interfaces_cmd);
|
||||||
|
@ -428,15 +428,14 @@ int pim_hello_recv(struct interface *ifp,
|
|||||||
return 0;
|
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,
|
uint8_t *tlv_buf, int tlv_buf_size,
|
||||||
uint16_t holdtime,
|
uint16_t holdtime,
|
||||||
uint32_t dr_priority,
|
uint32_t dr_priority,
|
||||||
uint32_t generation_id,
|
uint32_t generation_id,
|
||||||
uint16_t propagation_delay,
|
uint16_t propagation_delay,
|
||||||
uint16_t override_interval,
|
uint16_t override_interval,
|
||||||
int can_disable_join_suppression,
|
int can_disable_join_suppression)
|
||||||
struct list *ifconnected)
|
|
||||||
{
|
{
|
||||||
uint8_t *curr = tlv_buf;
|
uint8_t *curr = tlv_buf;
|
||||||
uint8_t *pastend = tlv_buf + tlv_buf_size;
|
uint8_t *pastend = tlv_buf + tlv_buf_size;
|
||||||
@ -454,7 +453,7 @@ int pim_hello_build_tlv(const char *ifname,
|
|||||||
if (!curr) {
|
if (!curr) {
|
||||||
if (PIM_DEBUG_PIM_HELLO) {
|
if (PIM_DEBUG_PIM_HELLO) {
|
||||||
zlog_debug("%s: could not set PIM hello Holdtime option for interface %s",
|
zlog_debug("%s: could not set PIM hello Holdtime option for interface %s",
|
||||||
__PRETTY_FUNCTION__, ifname);
|
__PRETTY_FUNCTION__, ifp->name);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -468,7 +467,7 @@ int pim_hello_build_tlv(const char *ifname,
|
|||||||
if (!tmp) {
|
if (!tmp) {
|
||||||
if (PIM_DEBUG_PIM_HELLO) {
|
if (PIM_DEBUG_PIM_HELLO) {
|
||||||
zlog_debug("%s: could not set PIM LAN Prune Delay option for interface %s",
|
zlog_debug("%s: could not set PIM LAN Prune Delay option for interface %s",
|
||||||
__PRETTY_FUNCTION__, ifname);
|
__PRETTY_FUNCTION__, ifp->name);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -485,7 +484,7 @@ int pim_hello_build_tlv(const char *ifname,
|
|||||||
if (!curr) {
|
if (!curr) {
|
||||||
if (PIM_DEBUG_PIM_HELLO) {
|
if (PIM_DEBUG_PIM_HELLO) {
|
||||||
zlog_debug("%s: could not set PIM hello DR Priority option for interface %s",
|
zlog_debug("%s: could not set PIM hello DR Priority option for interface %s",
|
||||||
__PRETTY_FUNCTION__, ifname);
|
__PRETTY_FUNCTION__, ifp->name);
|
||||||
}
|
}
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
@ -498,23 +497,38 @@ int pim_hello_build_tlv(const char *ifname,
|
|||||||
if (!curr) {
|
if (!curr) {
|
||||||
if (PIM_DEBUG_PIM_HELLO) {
|
if (PIM_DEBUG_PIM_HELLO) {
|
||||||
zlog_debug("%s: could not set PIM hello Generation ID option for interface %s",
|
zlog_debug("%s: could not set PIM hello Generation ID option for interface %s",
|
||||||
__PRETTY_FUNCTION__, ifname);
|
__PRETTY_FUNCTION__, ifp->name);
|
||||||
}
|
}
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Secondary Address List */
|
/* Secondary Address List */
|
||||||
if (ifconnected) {
|
if (ifp->connected->count) {
|
||||||
curr = pim_tlv_append_addrlist_ucast(curr,
|
curr = pim_tlv_append_addrlist_ucast(curr,
|
||||||
pastend,
|
pastend,
|
||||||
ifconnected);
|
ifp->connected,
|
||||||
|
AF_INET);
|
||||||
if (!curr) {
|
if (!curr) {
|
||||||
if (PIM_DEBUG_PIM_HELLO) {
|
if (PIM_DEBUG_PIM_HELLO) {
|
||||||
zlog_debug("%s: could not set PIM hello Secondary Address List option for interface %s",
|
zlog_debug("%s: could not set PIM hello v4 Secondary Address List option for interface %s",
|
||||||
__PRETTY_FUNCTION__, ifname);
|
__PRETTY_FUNCTION__, ifp->name);
|
||||||
}
|
}
|
||||||
return -4;
|
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;
|
return curr - tlv_buf;
|
||||||
|
@ -29,15 +29,14 @@ int pim_hello_recv(struct interface *ifp,
|
|||||||
struct in_addr src_addr,
|
struct in_addr src_addr,
|
||||||
uint8_t *tlv_buf, int tlv_buf_size);
|
uint8_t *tlv_buf, int tlv_buf_size);
|
||||||
|
|
||||||
int pim_hello_build_tlv(const char *ifname,
|
int pim_hello_build_tlv(struct interface *ifp,
|
||||||
uint8_t *tlv_buf, int tlv_buf_size,
|
uint8_t *tlv_buf, int tlv_buf_size,
|
||||||
uint16_t holdtime,
|
uint16_t holdtime,
|
||||||
uint32_t dr_priority,
|
uint32_t dr_priority,
|
||||||
uint32_t generation_id,
|
uint32_t generation_id,
|
||||||
uint16_t propagation_delay,
|
uint16_t propagation_delay,
|
||||||
uint16_t override_interval,
|
uint16_t override_interval,
|
||||||
int can_disable_join_suppression,
|
int can_disable_join_suppression);
|
||||||
struct list *ifconnected);
|
|
||||||
|
|
||||||
void pim_hello_require(struct interface *ifp);
|
void pim_hello_require(struct interface *ifp);
|
||||||
|
|
||||||
|
112
pimd/pim_iface.c
112
pimd/pim_iface.c
@ -30,6 +30,7 @@
|
|||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
|
||||||
#include "pimd.h"
|
#include "pimd.h"
|
||||||
|
#include "pim_zebra.h"
|
||||||
#include "pim_iface.h"
|
#include "pim_iface.h"
|
||||||
#include "pim_igmp.h"
|
#include "pim_igmp.h"
|
||||||
#include "pim_mroute.h"
|
#include "pim_mroute.h"
|
||||||
@ -42,6 +43,7 @@
|
|||||||
#include "pim_time.h"
|
#include "pim_time.h"
|
||||||
#include "pim_ssmpingd.h"
|
#include "pim_ssmpingd.h"
|
||||||
#include "pim_rp.h"
|
#include "pim_rp.h"
|
||||||
|
#include "pim_nht.h"
|
||||||
|
|
||||||
struct interface *pim_regiface = NULL;
|
struct interface *pim_regiface = NULL;
|
||||||
struct list *pim_ifchannel_list = NULL;
|
struct list *pim_ifchannel_list = NULL;
|
||||||
@ -324,12 +326,29 @@ static int pim_sec_addr_comp(const void *p1, const void *p2)
|
|||||||
const struct pim_secondary_addr *sec1 = p1;
|
const struct pim_secondary_addr *sec1 = p1;
|
||||||
const struct pim_secondary_addr *sec2 = p2;
|
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;
|
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;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,7 +358,7 @@ static void pim_sec_addr_free(struct pim_secondary_addr *sec_addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct pim_secondary_addr *
|
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 pim_secondary_addr *sec_addr;
|
||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
@ -349,7 +368,7 @@ pim_sec_addr_find(struct pim_interface *pim_ifp, struct in_addr addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
|
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;
|
return sec_addr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -364,7 +383,7 @@ static void pim_sec_addr_del(struct pim_interface *pim_ifp,
|
|||||||
pim_sec_addr_free(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;
|
int changed = 0;
|
||||||
struct pim_secondary_addr *sec_addr;
|
struct pim_secondary_addr *sec_addr;
|
||||||
@ -391,7 +410,7 @@ static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct in_addr addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
changed = 1;
|
changed = 1;
|
||||||
sec_addr->addr = addr;
|
sec_addr->addr = *addr;
|
||||||
listnode_add_sort(pim_ifp->sec_addr_list, sec_addr);
|
listnode_add_sort(pim_ifp->sec_addr_list, sec_addr);
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
@ -433,10 +452,6 @@ static int pim_sec_addr_update(struct interface *ifp)
|
|||||||
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
|
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
|
||||||
struct prefix *p = ifc->address;
|
struct prefix *p = ifc->address;
|
||||||
|
|
||||||
if (p->family != AF_INET) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
|
if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -446,7 +461,7 @@ static int pim_sec_addr_update(struct interface *ifp)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pim_sec_addr_add(pim_ifp, p->u.prefix4)) {
|
if (pim_sec_addr_add(pim_ifp, p)) {
|
||||||
changed = 1;
|
changed = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -571,33 +586,55 @@ void pim_if_addr_add(struct connected *ifc)
|
|||||||
|
|
||||||
detect_address_change(ifp, 0, __PRETTY_FUNCTION__);
|
detect_address_change(ifp, 0, __PRETTY_FUNCTION__);
|
||||||
|
|
||||||
|
if (ifc->address->family != AF_INET)
|
||||||
|
return;
|
||||||
|
|
||||||
if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
|
if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
|
||||||
struct igmp_sock *igmp;
|
struct igmp_sock *igmp;
|
||||||
|
|
||||||
/* lookup IGMP socket */
|
/* lookup IGMP socket */
|
||||||
igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
|
igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
|
||||||
ifaddr);
|
ifaddr);
|
||||||
if (!igmp) {
|
if (!igmp) {
|
||||||
/* if addr new, add IGMP socket */
|
/* if addr new, add IGMP socket */
|
||||||
pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp);
|
pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp);
|
||||||
}
|
}
|
||||||
} /* igmp */
|
} /* igmp */
|
||||||
|
|
||||||
if (PIM_IF_TEST_PIM(pim_ifp->options)) {
|
if (PIM_IF_TEST_PIM(pim_ifp->options))
|
||||||
|
{
|
||||||
|
|
||||||
/* Interface has a valid primary address ? */
|
if (PIM_INADDR_ISNOT_ANY (pim_ifp->primary_address))
|
||||||
if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
|
{
|
||||||
|
|
||||||
/* Interface has a valid socket ? */
|
/* Interface has a valid socket ? */
|
||||||
if (pim_ifp->pim_sock_fd < 0) {
|
if (pim_ifp->pim_sock_fd < 0)
|
||||||
if (pim_sock_add(ifp)) {
|
{
|
||||||
zlog_warn("Failure creating PIM socket for interface %s",
|
if (pim_sock_add (ifp))
|
||||||
ifp->name);
|
{
|
||||||
}
|
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 ();
|
||||||
} /* pim */
|
/* 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
|
PIM or IGMP is enabled on interface, and there is at least one
|
||||||
@ -675,14 +712,17 @@ void pim_if_addr_del(struct connected *ifc, int force_prim_as_any)
|
|||||||
ifp = ifc->ifp;
|
ifp = ifc->ifp;
|
||||||
zassert(ifp);
|
zassert(ifp);
|
||||||
|
|
||||||
|
if (ifc->address->family != AF_INET)
|
||||||
|
return;
|
||||||
|
|
||||||
if (PIM_DEBUG_ZEBRA) {
|
if (PIM_DEBUG_ZEBRA) {
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
prefix2str(ifc->address, buf, BUFSIZ);
|
prefix2str(ifc->address, buf, BUFSIZ);
|
||||||
zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
|
zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
|
||||||
__PRETTY_FUNCTION__,
|
__PRETTY_FUNCTION__,
|
||||||
ifp->name, ifp->ifindex, buf,
|
ifp->name, ifp->ifindex, buf,
|
||||||
CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
|
CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
|
||||||
"secondary" : "primary");
|
"secondary" : "primary");
|
||||||
}
|
}
|
||||||
|
|
||||||
detect_address_change(ifp, force_prim_as_any, __PRETTY_FUNCTION__);
|
detect_address_change(ifp, force_prim_as_any, __PRETTY_FUNCTION__);
|
||||||
@ -709,12 +749,9 @@ void pim_if_addr_add_all(struct interface *ifp)
|
|||||||
struct prefix *p = ifc->address;
|
struct prefix *p = ifc->address;
|
||||||
|
|
||||||
if (p->family != AF_INET)
|
if (p->family != AF_INET)
|
||||||
{
|
v6_addrs++;
|
||||||
v6_addrs++;
|
else
|
||||||
continue;
|
v4_addrs++;
|
||||||
}
|
|
||||||
|
|
||||||
v4_addrs++;
|
|
||||||
pim_if_addr_add(ifc);
|
pim_if_addr_add(ifc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1105,6 +1142,7 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
|
|||||||
struct listnode *neighnode;
|
struct listnode *neighnode;
|
||||||
struct pim_neighbor *neigh;
|
struct pim_neighbor *neigh;
|
||||||
struct pim_interface *pim_ifp;
|
struct pim_interface *pim_ifp;
|
||||||
|
struct prefix p;
|
||||||
|
|
||||||
zassert(ifp);
|
zassert(ifp);
|
||||||
|
|
||||||
@ -1116,6 +1154,10 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
|
|||||||
return 0;
|
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)) {
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) {
|
||||||
|
|
||||||
/* primary address ? */
|
/* primary address ? */
|
||||||
@ -1123,7 +1165,7 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
|
|||||||
return neigh;
|
return neigh;
|
||||||
|
|
||||||
/* secondary address ? */
|
/* secondary address ? */
|
||||||
if (pim_neighbor_find_secondary(neigh, addr))
|
if (pim_neighbor_find_secondary(neigh, &p))
|
||||||
return neigh;
|
return neigh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ enum pim_secondary_addr_flags {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct pim_secondary_addr {
|
struct pim_secondary_addr {
|
||||||
struct in_addr addr;
|
struct prefix addr;
|
||||||
enum pim_secondary_addr_flags flags;
|
enum pim_secondary_addr_flags flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1006,6 +1006,8 @@ pim_ifchannel_local_membership_add(struct interface *ifp,
|
|||||||
pim_upstream_switch (child, PIM_UPSTREAM_JOINED);
|
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;
|
return 1;
|
||||||
|
@ -178,6 +178,15 @@ pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg
|
|||||||
|
|
||||||
up->channel_oil->cc.pktcnt++;
|
up->channel_oil->cc.pktcnt++;
|
||||||
PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
|
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);
|
pim_register_join (up);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -200,6 +209,30 @@ pim_mroute_msg_wholepkt (int fd, struct interface *ifp, const char *buf)
|
|||||||
|
|
||||||
up = pim_upstream_find(&sg);
|
up = pim_upstream_find(&sg);
|
||||||
if (!up) {
|
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) {
|
if (PIM_DEBUG_MROUTE_DETAIL) {
|
||||||
zlog_debug("%s: Unable to find upstream channel WHOLEPKT%s",
|
zlog_debug("%s: Unable to find upstream channel WHOLEPKT%s",
|
||||||
__PRETTY_FUNCTION__, pim_str_sg_dump (&sg));
|
__PRETTY_FUNCTION__, pim_str_sg_dump (&sg));
|
||||||
@ -858,9 +891,8 @@ int pim_mroute_del (struct channel_oil *c_oil, const char *name)
|
|||||||
pim_channel_oil_dump (c_oil, buf, sizeof(buf)));
|
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->installed = 0;
|
||||||
c_oil->oil.mfcc_parent = MAXVIFS;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,11 @@
|
|||||||
From:
|
From:
|
||||||
http://www.iana.org/assignments/address-family-numbers
|
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
|
* Network Order pim_msg_hdr
|
||||||
|
@ -423,6 +423,31 @@ void pim_neighbor_free(struct pim_neighbor *neigh)
|
|||||||
XFREE(MTYPE_PIM_NEIGHBOR, neigh);
|
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 pim_neighbor *pim_neighbor_find(struct interface *ifp,
|
||||||
struct in_addr source_addr)
|
struct in_addr source_addr)
|
||||||
{
|
{
|
||||||
@ -502,6 +527,12 @@ struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
|
|||||||
|
|
||||||
listnode_add(pim_ifp->pim_neighbor_list, neigh);
|
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
|
RFC 4601: 4.3.2. DR Election
|
||||||
|
|
||||||
@ -532,6 +563,14 @@ struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
|
|||||||
|
|
||||||
pim_upstream_find_new_rpf();
|
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_rp_setup ();
|
||||||
|
|
||||||
pim_neighbor_rpf_update();
|
pim_neighbor_rpf_update();
|
||||||
@ -669,7 +708,7 @@ void pim_neighbor_delete_all(struct interface *ifp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
|
struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
|
||||||
struct in_addr addr)
|
struct prefix *addr)
|
||||||
{
|
{
|
||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
struct prefix *p;
|
struct prefix *p;
|
||||||
@ -678,14 +717,11 @@ struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) {
|
for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) {
|
||||||
if (p->family == AF_INET) {
|
if (prefix_same (p, addr))
|
||||||
if (addr.s_addr == p->u.prefix4.s_addr) {
|
return p;
|
||||||
return p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -729,7 +765,7 @@ static void delete_from_neigh_addr(struct interface *ifp,
|
|||||||
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node,
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node,
|
||||||
neigh)) {
|
neigh)) {
|
||||||
{
|
{
|
||||||
struct prefix *p = pim_neighbor_find_secondary(neigh, addr->u.prefix4);
|
struct prefix *p = pim_neighbor_find_secondary(neigh, addr);
|
||||||
if (p) {
|
if (p) {
|
||||||
char addr_str[INET_ADDRSTRLEN];
|
char addr_str[INET_ADDRSTRLEN];
|
||||||
char this_neigh_str[INET_ADDRSTRLEN];
|
char this_neigh_str[INET_ADDRSTRLEN];
|
||||||
|
@ -50,7 +50,8 @@ void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime);
|
|||||||
void pim_neighbor_free(struct pim_neighbor *neigh);
|
void pim_neighbor_free(struct pim_neighbor *neigh);
|
||||||
struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
|
struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
|
||||||
struct in_addr source_addr);
|
struct in_addr source_addr);
|
||||||
|
struct pim_neighbor *pim_neighbor_find_by_secondary (struct interface *ifp,
|
||||||
|
struct prefix *src);
|
||||||
struct pim_neighbor *pim_neighbor_find_if (struct interface *ifp);
|
struct pim_neighbor *pim_neighbor_find_if (struct interface *ifp);
|
||||||
|
|
||||||
|
|
||||||
@ -77,7 +78,7 @@ void pim_neighbor_update(struct pim_neighbor *neigh,
|
|||||||
uint32_t dr_priority,
|
uint32_t dr_priority,
|
||||||
struct list *addr_list);
|
struct list *addr_list);
|
||||||
struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
|
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);
|
int pim_if_dr_election(struct interface *ifp);
|
||||||
|
|
||||||
#endif /* PIM_NEIGHBOR_H */
|
#endif /* PIM_NEIGHBOR_H */
|
||||||
|
561
pimd/pim_nht.c
561
pimd/pim_nht.c
@ -39,12 +39,13 @@
|
|||||||
#include "pim_join.h"
|
#include "pim_join.h"
|
||||||
#include "pim_jp_agg.h"
|
#include "pim_jp_agg.h"
|
||||||
#include "pim_zebra.h"
|
#include "pim_zebra.h"
|
||||||
|
#include "pim_zlookup.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
|
* pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
|
||||||
* command to Zebra.
|
* command to Zebra.
|
||||||
*/
|
*/
|
||||||
static void
|
void
|
||||||
pim_sendmsg_zebra_rnh (struct zclient *zclient, struct pim_nexthop_cache *pnc,
|
pim_sendmsg_zebra_rnh (struct zclient *zclient, struct pim_nexthop_cache *pnc,
|
||||||
int command)
|
int command)
|
||||||
{
|
{
|
||||||
@ -87,9 +88,9 @@ pim_sendmsg_zebra_rnh (struct zclient *zclient, struct pim_nexthop_cache *pnc,
|
|||||||
{
|
{
|
||||||
char buf[PREFIX2STR_BUFFER];
|
char buf[PREFIX2STR_BUFFER];
|
||||||
prefix2str (p, buf, sizeof (buf));
|
prefix2str (p, buf, sizeof (buf));
|
||||||
zlog_debug ("%s: NHT Addr %s %sregistered with Zebra ret:%d ",
|
zlog_debug ("%s: NHT %sregistered addr %s with Zebra ret:%d ",
|
||||||
__PRETTY_FUNCTION__, buf,
|
__PRETTY_FUNCTION__,
|
||||||
(command == ZEBRA_NEXTHOP_REGISTER) ? " " : "de", ret);
|
(command == ZEBRA_NEXTHOP_REGISTER) ? " " : "de", buf, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -149,7 +150,8 @@ pim_nexthop_cache_add (struct pim_rpf *rpf_addr)
|
|||||||
/* This API is used to Register an address with Zebra */
|
/* This API is used to Register an address with Zebra */
|
||||||
int
|
int
|
||||||
pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up,
|
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_nexthop_cache *pnc = NULL;
|
||||||
struct pim_rpf rpf;
|
struct pim_rpf rpf;
|
||||||
@ -174,11 +176,14 @@ pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up,
|
|||||||
}
|
}
|
||||||
pnc = pim_nexthop_cache_add (&rpf);
|
pnc = pim_nexthop_cache_add (&rpf);
|
||||||
if (pnc)
|
if (pnc)
|
||||||
pim_sendmsg_zebra_rnh (zclient, pnc,
|
pim_sendmsg_zebra_rnh (zclient, pnc, ZEBRA_NEXTHOP_REGISTER);
|
||||||
ZEBRA_NEXTHOP_REGISTER);
|
|
||||||
else
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +197,7 @@ pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up,
|
|||||||
char rp_str[PREFIX_STRLEN];
|
char rp_str[PREFIX_STRLEN];
|
||||||
pim_addr_dump ("<rp?>", &rp->rp.rpf_addr, rp_str,
|
pim_addr_dump ("<rp?>", &rp->rp.rpf_addr, rp_str,
|
||||||
sizeof (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);
|
__PRETTY_FUNCTION__, rp_str);
|
||||||
}
|
}
|
||||||
listnode_add_sort (pnc->rp_list, rp);
|
listnode_add_sort (pnc->rp_list, rp);
|
||||||
@ -209,15 +214,18 @@ pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up,
|
|||||||
char buf[PREFIX2STR_BUFFER];
|
char buf[PREFIX2STR_BUFFER];
|
||||||
prefix2str (addr, buf, sizeof (buf));
|
prefix2str (addr, buf, sizeof (buf));
|
||||||
zlog_debug
|
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);
|
__PRETTY_FUNCTION__, up->sg_str, buf);
|
||||||
}
|
}
|
||||||
listnode_add_sort (pnc->upstream_list, up);
|
listnode_add_sort (pnc->upstream_list, up);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CHECK_FLAG (pnc->flags, PIM_NEXTHOP_VALID))
|
if (pnc && CHECK_FLAG (pnc->flags, PIM_NEXTHOP_VALID))
|
||||||
return 1;
|
{
|
||||||
|
memcpy (out_pnc, pnc, sizeof (struct pim_nexthop_cache));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -249,8 +257,7 @@ pim_delete_tracked_nexthop (struct prefix *addr, struct pim_upstream *up,
|
|||||||
|
|
||||||
if (pnc->rp_list->count == 0 && pnc->upstream_list->count == 0)
|
if (pnc->rp_list->count == 0 && pnc->upstream_list->count == 0)
|
||||||
{
|
{
|
||||||
pim_sendmsg_zebra_rnh (zclient, pnc,
|
pim_sendmsg_zebra_rnh (zclient, pnc, ZEBRA_NEXTHOP_UNREGISTER);
|
||||||
ZEBRA_NEXTHOP_UNREGISTER);
|
|
||||||
|
|
||||||
list_delete (pnc->rp_list);
|
list_delete (pnc->rp_list);
|
||||||
list_delete (pnc->upstream_list);
|
list_delete (pnc->upstream_list);
|
||||||
@ -277,21 +284,16 @@ pim_update_rp_nh (struct pim_nexthop_cache *pnc)
|
|||||||
if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
|
if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (pim_nexthop_lookup (&rp_info->rp.source_nexthop,
|
//Compute PIM RPF using cached nexthop
|
||||||
rp_info->rp.rpf_addr.u.prefix4, 1) != 0)
|
pim_ecmp_nexthop_search (pnc, &rp_info->rp.source_nexthop,
|
||||||
{
|
&rp_info->rp.rpf_addr, &rp_info->group, 1);
|
||||||
if (PIM_DEBUG_PIM_TRACE)
|
|
||||||
zlog_debug ("Unable to lookup nexthop for rp specified");
|
|
||||||
ret++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PIM_DEBUG_TRACE)
|
if (PIM_DEBUG_TRACE)
|
||||||
{
|
{
|
||||||
char rp_str[PREFIX_STRLEN];
|
char rp_str[PREFIX_STRLEN];
|
||||||
pim_addr_dump ("<rp?>", &rp_info->rp.rpf_addr, rp_str,
|
pim_addr_dump ("<rp?>", &rp_info->rp.rpf_addr, rp_str,
|
||||||
sizeof (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,
|
__PRETTY_FUNCTION__, rp_str,
|
||||||
rp_info->rp.source_nexthop.interface->name);
|
rp_info->rp.source_nexthop.interface->name);
|
||||||
}
|
}
|
||||||
@ -304,6 +306,48 @@ pim_update_rp_nh (struct pim_nexthop_cache *pnc)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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.*/
|
/* Update Upstream nexthop info based on Nexthop update received from Zebra.*/
|
||||||
static int
|
static int
|
||||||
pim_update_upstream_nh (struct pim_nexthop_cache *pnc)
|
pim_update_upstream_nh (struct pim_nexthop_cache *pnc)
|
||||||
@ -312,8 +356,8 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc)
|
|||||||
struct listnode *ifnode;
|
struct listnode *ifnode;
|
||||||
struct listnode *up_nextnode;
|
struct listnode *up_nextnode;
|
||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
struct pim_upstream *up;
|
struct pim_upstream *up = NULL;
|
||||||
struct interface *ifp;
|
struct interface *ifp = NULL;
|
||||||
int vif_index = 0;
|
int vif_index = 0;
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS (pnc->upstream_list, up_node, up_nextnode, up))
|
for (ALL_LIST_ELEMENTS (pnc->upstream_list, up_node, up_nextnode, up))
|
||||||
@ -326,6 +370,26 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc)
|
|||||||
if (rpf_result == PIM_RPF_FAILURE)
|
if (rpf_result == PIM_RPF_FAILURE)
|
||||||
continue;
|
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)
|
if (rpf_result == PIM_RPF_CHANGED)
|
||||||
{
|
{
|
||||||
struct pim_neighbor *nbr;
|
struct pim_neighbor *nbr;
|
||||||
@ -377,7 +441,7 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc)
|
|||||||
returning PIM_RPF_CHANGED ? */
|
returning PIM_RPF_CHANGED ? */
|
||||||
pim_upstream_update_join_desired (up);
|
pim_upstream_update_join_desired (up);
|
||||||
|
|
||||||
} /* PIM_RPF_CHANGED */
|
} /* PIM_RPF_CHANGED */
|
||||||
|
|
||||||
if (PIM_DEBUG_TRACE)
|
if (PIM_DEBUG_TRACE)
|
||||||
{
|
{
|
||||||
@ -386,26 +450,7 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc)
|
|||||||
old.source_nexthop.interface->name,
|
old.source_nexthop.interface->name,
|
||||||
up->rpf.source_nexthop.interface->name);
|
up->rpf.source_nexthop.interface->name);
|
||||||
}
|
}
|
||||||
/* update kernel multicast forwarding cache (MFC) */
|
} /* for (pnc->upstream_list) */
|
||||||
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 (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp))
|
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp))
|
||||||
if (ifp->info)
|
if (ifp->info)
|
||||||
@ -426,10 +471,209 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
uint32_t
|
||||||
* This API is used to parse Registered address nexthop update
|
pim_compute_ecmp_hash (struct prefix * src, struct prefix * grp)
|
||||||
* coming from Zebra
|
{
|
||||||
*/
|
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
|
int
|
||||||
pim_parse_nexthop_update (int command, struct zclient *zclient,
|
pim_parse_nexthop_update (int command, struct zclient *zclient,
|
||||||
zebra_size_t length, vrf_id_t vrf_id)
|
zebra_size_t length, vrf_id_t vrf_id)
|
||||||
@ -437,7 +681,6 @@ pim_parse_nexthop_update (int command, struct zclient *zclient,
|
|||||||
struct stream *s;
|
struct stream *s;
|
||||||
struct prefix p;
|
struct prefix p;
|
||||||
struct nexthop *nexthop;
|
struct nexthop *nexthop;
|
||||||
struct nexthop *oldnh;
|
|
||||||
struct nexthop *nhlist_head = NULL;
|
struct nexthop *nhlist_head = NULL;
|
||||||
struct nexthop *nhlist_tail = NULL;
|
struct nexthop *nhlist_tail = NULL;
|
||||||
uint32_t metric, distance;
|
uint32_t metric, distance;
|
||||||
@ -476,8 +719,9 @@ pim_parse_nexthop_update (int command, struct zclient *zclient,
|
|||||||
{
|
{
|
||||||
char buf[PREFIX2STR_BUFFER];
|
char buf[PREFIX2STR_BUFFER];
|
||||||
prefix2str (&rpf.rpf_addr, buf, sizeof (buf));
|
prefix2str (&rpf.rpf_addr, buf, sizeof (buf));
|
||||||
zlog_debug ("%s: NHT addr %s is not in local cached DB.",
|
zlog_debug
|
||||||
__PRETTY_FUNCTION__, buf);
|
("%s: Skipping NHT update, addr %s is not in local cached DB.",
|
||||||
|
__PRETTY_FUNCTION__, buf);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -490,7 +734,7 @@ pim_parse_nexthop_update (int command, struct zclient *zclient,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pnc->last_update = pim_time_monotonic_sec ();
|
pnc->last_update = pim_time_monotonic_usec ();
|
||||||
distance = stream_getc (s);
|
distance = stream_getc (s);
|
||||||
metric = stream_getl (s);
|
metric = stream_getl (s);
|
||||||
nexthop_num = stream_getc (s);
|
nexthop_num = stream_getc (s);
|
||||||
@ -499,17 +743,15 @@ pim_parse_nexthop_update (int command, struct zclient *zclient,
|
|||||||
{
|
{
|
||||||
char buf[PREFIX2STR_BUFFER];
|
char buf[PREFIX2STR_BUFFER];
|
||||||
prefix2str (&p, buf, sizeof (buf));
|
prefix2str (&p, buf, sizeof (buf));
|
||||||
zlog_debug ("%s: NHT Update for %s nexthop_num %d vrf:%d upcount %d rpcount %d",
|
zlog_debug
|
||||||
__PRETTY_FUNCTION__, buf, nexthop_num, vrf_id,
|
("%s: NHT Update for %s nexthop_num %d vrf:%d upcount %d rpcount %d",
|
||||||
listcount (pnc->upstream_list), listcount (pnc->rp_list));
|
__PRETTY_FUNCTION__, buf, nexthop_num, vrf_id,
|
||||||
|
listcount (pnc->upstream_list), listcount (pnc->rp_list));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nexthop_num)
|
if (nexthop_num)
|
||||||
{
|
{
|
||||||
pnc->flags |= PIM_NEXTHOP_VALID;
|
pnc->nexthop_num = 0; //Only increment for pim enabled rpf.
|
||||||
pnc->distance = distance;
|
|
||||||
pnc->metric = metric;
|
|
||||||
pnc->nexthop_num = nexthop_num;
|
|
||||||
|
|
||||||
for (i = 0; i < nexthop_num; i++)
|
for (i = 0; i < nexthop_num; i++)
|
||||||
{
|
{
|
||||||
@ -539,7 +781,34 @@ pim_parse_nexthop_update (int command, struct zclient *zclient,
|
|||||||
(nexthop->ifindex, VRF_DEFAULT));
|
(nexthop->ifindex, VRF_DEFAULT));
|
||||||
/* Overwrite with Nbr address as NH addr */
|
/* Overwrite with Nbr address as NH addr */
|
||||||
if (nbr)
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -562,9 +831,10 @@ pim_parse_nexthop_update (int command, struct zclient *zclient,
|
|||||||
if (PIM_DEBUG_ZEBRA)
|
if (PIM_DEBUG_ZEBRA)
|
||||||
{
|
{
|
||||||
char buf[NEXTHOP_STRLEN];
|
char buf[NEXTHOP_STRLEN];
|
||||||
zlog_debug("%s: could not find interface for ifindex %d (addr %s)",
|
zlog_debug
|
||||||
__PRETTY_FUNCTION__,
|
("%s: could not find interface for ifindex %d (addr %s)",
|
||||||
nexthop->ifindex, nexthop2str (nexthop, buf, sizeof (buf)));
|
__PRETTY_FUNCTION__, nexthop->ifindex,
|
||||||
|
nexthop2str (nexthop, buf, sizeof (buf)));
|
||||||
}
|
}
|
||||||
nexthop_free (nexthop);
|
nexthop_free (nexthop);
|
||||||
continue;
|
continue;
|
||||||
@ -594,14 +864,18 @@ pim_parse_nexthop_update (int command, struct zclient *zclient,
|
|||||||
nhlist_tail = nexthop;
|
nhlist_tail = nexthop;
|
||||||
nhlist_head = nexthop;
|
nhlist_head = nexthop;
|
||||||
}
|
}
|
||||||
|
//Only keep track of nexthops which are PIM enabled.
|
||||||
for (oldnh = pnc->nexthop; oldnh; oldnh = oldnh->next)
|
pnc->nexthop_num++;
|
||||||
if (nexthop_same_no_recurse (oldnh, nexthop))
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
/* Reset existing pnc->nexthop before assigning new list */
|
/* Reset existing pnc->nexthop before assigning new list */
|
||||||
nexthops_free (pnc->nexthop);
|
nexthops_free (pnc->nexthop);
|
||||||
pnc->nexthop = nhlist_head;
|
pnc->nexthop = nhlist_head;
|
||||||
|
if (pnc->nexthop_num)
|
||||||
|
{
|
||||||
|
pnc->flags |= PIM_NEXTHOP_VALID;
|
||||||
|
pnc->distance = distance;
|
||||||
|
pnc->metric = metric;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -611,6 +885,16 @@ pim_parse_nexthop_update (int command, struct zclient *zclient,
|
|||||||
pnc->nexthop = NULL;
|
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 ();
|
pim_rpf_set_refresh_time ();
|
||||||
|
|
||||||
if (listcount (pnc->rp_list))
|
if (listcount (pnc->rp_list))
|
||||||
@ -620,3 +904,142 @@ pim_parse_nexthop_update (int command, struct zclient *zclient,
|
|||||||
|
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
@ -51,10 +51,19 @@ struct pim_nexthop_cache
|
|||||||
int pim_parse_nexthop_update (int command, struct zclient *zclient,
|
int pim_parse_nexthop_update (int command, struct zclient *zclient,
|
||||||
zebra_size_t length, vrf_id_t vrf_id);
|
zebra_size_t length, vrf_id_t vrf_id);
|
||||||
int pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up,
|
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,
|
void pim_delete_tracked_nexthop (struct prefix *addr, struct pim_upstream *up,
|
||||||
struct rp_info *rp);
|
struct rp_info *rp);
|
||||||
struct pim_nexthop_cache *pim_nexthop_cache_add (struct pim_rpf *rpf_addr);
|
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);
|
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
|
#endif
|
||||||
|
@ -289,10 +289,10 @@ pim_channel_del_oif (struct channel_oil *channel_oil,
|
|||||||
char source_str[INET_ADDRSTRLEN];
|
char source_str[INET_ADDRSTRLEN];
|
||||||
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
|
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
|
||||||
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
|
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
|
||||||
zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
|
zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u IIF:%d OIF=%s vif_index=%d",
|
||||||
__FILE__, __PRETTY_FUNCTION__,
|
__FILE__, __PRETTY_FUNCTION__,
|
||||||
source_str, group_str,
|
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;
|
return 0;
|
||||||
|
@ -627,7 +627,7 @@ static int hello_send(struct interface *ifp,
|
|||||||
listcount(ifp->connected));
|
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,
|
pim_msg + PIM_PIM_MIN_LEN,
|
||||||
sizeof(pim_msg) - PIM_PIM_MIN_LEN,
|
sizeof(pim_msg) - PIM_PIM_MIN_LEN,
|
||||||
holdtime,
|
holdtime,
|
||||||
@ -635,8 +635,7 @@ static int hello_send(struct interface *ifp,
|
|||||||
pim_ifp->pim_generation_id,
|
pim_ifp->pim_generation_id,
|
||||||
pim_ifp->pim_propagation_delay_msec,
|
pim_ifp->pim_propagation_delay_msec,
|
||||||
pim_ifp->pim_override_interval_msec,
|
pim_ifp->pim_override_interval_msec,
|
||||||
PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
|
PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options));
|
||||||
ifp->connected);
|
|
||||||
if (pim_tlv_size < 0) {
|
if (pim_tlv_size < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -187,6 +187,15 @@ pim_register_send (const uint8_t *buf, int buf_size, struct in_addr src, struct
|
|||||||
return;
|
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);
|
memset(buffer, 0, 10000);
|
||||||
b1 = buffer + PIM_MSG_HEADER_LEN;
|
b1 = buffer + PIM_MSG_HEADER_LEN;
|
||||||
*b1 |= null_register << 6;
|
*b1 |= null_register << 6;
|
||||||
|
176
pimd/pim_rp.c
176
pimd/pim_rp.c
@ -30,6 +30,7 @@
|
|||||||
#include "vty.h"
|
#include "vty.h"
|
||||||
#include "vrf.h"
|
#include "vrf.h"
|
||||||
#include "plist.h"
|
#include "plist.h"
|
||||||
|
#include "nexthop.h"
|
||||||
|
|
||||||
#include "pimd.h"
|
#include "pimd.h"
|
||||||
#include "pim_vty.h"
|
#include "pim_vty.h"
|
||||||
@ -249,7 +250,7 @@ pim_rp_check_interface_addrs(struct rp_info *rp_info,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -280,7 +281,7 @@ pim_rp_check_interfaces (struct rp_info *rp_info)
|
|||||||
int
|
int
|
||||||
pim_rp_new (const char *rp, const char *group_range, const char *plist)
|
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_info;
|
||||||
struct rp_info *rp_all;
|
struct rp_info *rp_all;
|
||||||
struct prefix group_all;
|
struct prefix group_all;
|
||||||
@ -288,6 +289,7 @@ pim_rp_new (const char *rp, const char *group_range, const char *plist)
|
|||||||
struct rp_info *tmp_rp_info;
|
struct rp_info *tmp_rp_info;
|
||||||
char buffer[BUFSIZ];
|
char buffer[BUFSIZ];
|
||||||
struct prefix nht_p;
|
struct prefix nht_p;
|
||||||
|
struct pim_nexthop_cache pnc;
|
||||||
|
|
||||||
rp_info = XCALLOC (MTYPE_PIM_RP, sizeof (*rp_info));
|
rp_info = XCALLOC (MTYPE_PIM_RP, sizeof (*rp_info));
|
||||||
if (!rp_info)
|
if (!rp_info)
|
||||||
@ -387,21 +389,31 @@ pim_rp_new (const char *rp, const char *group_range, const char *plist)
|
|||||||
/* Register addr with Zebra NHT */
|
/* Register addr with Zebra NHT */
|
||||||
nht_p.family = AF_INET;
|
nht_p.family = AF_INET;
|
||||||
nht_p.prefixlen = IPV4_MAX_BITLEN;
|
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)
|
if (PIM_DEBUG_PIM_TRACE)
|
||||||
{
|
{
|
||||||
char buf[PREFIX2STR_BUFFER];
|
char buf[PREFIX2STR_BUFFER];
|
||||||
|
char buf1[PREFIX2STR_BUFFER];
|
||||||
prefix2str (&nht_p, buf, sizeof (buf));
|
prefix2str (&nht_p, buf, sizeof (buf));
|
||||||
zlog_debug ("%s: NHT Register rp_all addr %s with NHT ",
|
prefix2str (&rp_all->group, buf1, sizeof (buf1));
|
||||||
__PRETTY_FUNCTION__, buf);
|
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_check_interfaces (rp_all);
|
||||||
pim_rp_refresh_group_to_rp_mapping();
|
pim_rp_refresh_group_to_rp_mapping ();
|
||||||
return PIM_SUCCESS;
|
return PIM_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,13 +463,25 @@ pim_rp_new (const char *rp, const char *group_range, const char *plist)
|
|||||||
if (PIM_DEBUG_PIM_TRACE)
|
if (PIM_DEBUG_PIM_TRACE)
|
||||||
{
|
{
|
||||||
char buf[PREFIX2STR_BUFFER];
|
char buf[PREFIX2STR_BUFFER];
|
||||||
|
char buf1[PREFIX2STR_BUFFER];
|
||||||
prefix2str (&nht_p, buf, sizeof (buf));
|
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)
|
memset (&pnc, 0, sizeof (struct pim_nexthop_cache));
|
||||||
return PIM_RP_NO_PATH;
|
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_check_interfaces (rp_info);
|
||||||
pim_rp_refresh_group_to_rp_mapping ();
|
pim_rp_refresh_group_to_rp_mapping ();
|
||||||
@ -509,7 +533,8 @@ pim_rp_del (const char *rp, const char *group_range, const char *plist)
|
|||||||
{
|
{
|
||||||
char buf[PREFIX2STR_BUFFER];
|
char buf[PREFIX2STR_BUFFER];
|
||||||
prefix2str (&nht_p, buf, sizeof (buf));
|
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);
|
pim_delete_tracked_nexthop (&nht_p, NULL, rp_info);
|
||||||
|
|
||||||
@ -535,17 +560,39 @@ pim_rp_setup (void)
|
|||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
struct rp_info *rp_info;
|
struct rp_info *rp_info;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
struct prefix nht_p;
|
||||||
|
struct pim_nexthop_cache pnc;
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
|
for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
|
||||||
{
|
{
|
||||||
if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
|
if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
|
||||||
continue;
|
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)
|
//Compute PIM RPF using Cached nexthop
|
||||||
zlog_debug ("Unable to lookup nexthop for rp specified");
|
pim_ecmp_nexthop_search (&pnc, &rp_info->rp.source_nexthop,
|
||||||
ret++;
|
&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++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -680,7 +727,43 @@ pim_rp_g (struct in_addr group)
|
|||||||
|
|
||||||
if (rp_info)
|
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);
|
return (&rp_info->rp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -862,3 +945,54 @@ pim_rp_show_information (struct vty *vty, u_char uj)
|
|||||||
json_object_free(json);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -61,6 +61,6 @@ struct pim_rpf *pim_rp_g (struct in_addr group);
|
|||||||
#define RP(G) pim_rp_g ((G))
|
#define RP(G) pim_rp_g ((G))
|
||||||
|
|
||||||
void pim_rp_show_information (struct vty *vty, u_char uj);
|
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);
|
int pim_rp_list_cmp (void *v1, void *v2);
|
||||||
#endif
|
#endif
|
||||||
|
@ -67,11 +67,14 @@ int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, int nei
|
|||||||
{
|
{
|
||||||
char addr_str[INET_ADDRSTRLEN];
|
char addr_str[INET_ADDRSTRLEN];
|
||||||
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
|
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
|
||||||
zlog_debug ("%s: 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__,
|
__PRETTY_FUNCTION__,
|
||||||
addr_str,
|
addr_str,
|
||||||
nexthop->last_lookup_time,
|
nexthop->last_lookup_time,
|
||||||
last_route_change_time);
|
last_route_change_time, nexthop_str);
|
||||||
}
|
}
|
||||||
nexthop_lookups_avoided++;
|
nexthop_lookups_avoided++;
|
||||||
return 0;
|
return 0;
|
||||||
@ -190,32 +193,56 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old,
|
|||||||
struct pim_rpf *rpf = &up->rpf;
|
struct pim_rpf *rpf = &up->rpf;
|
||||||
struct pim_rpf saved;
|
struct pim_rpf saved;
|
||||||
struct prefix nht_p;
|
struct prefix nht_p;
|
||||||
|
struct pim_nexthop_cache pnc;
|
||||||
|
int ret = 0;
|
||||||
|
struct prefix src, grp;
|
||||||
|
|
||||||
saved.source_nexthop = rpf->source_nexthop;
|
saved.source_nexthop = rpf->source_nexthop;
|
||||||
saved.rpf_addr = rpf->rpf_addr;
|
saved.rpf_addr = rpf->rpf_addr;
|
||||||
|
|
||||||
if (is_new)
|
if (is_new && PIM_DEBUG_ZEBRA)
|
||||||
{
|
{
|
||||||
if (PIM_DEBUG_ZEBRA)
|
char source_str[INET_ADDRSTRLEN];
|
||||||
{
|
pim_inet4_dump ("<source?>", up->upstream_addr, source_str,
|
||||||
char source_str[INET_ADDRSTRLEN];
|
sizeof (source_str));
|
||||||
pim_inet4_dump("<source?>", up->upstream_addr, source_str, sizeof(source_str));
|
zlog_debug ("%s: NHT Register upstream %s addr %s with Zebra.",
|
||||||
zlog_debug ("%s: NHT Register upstream %s addr %s with Zebra.",
|
__PRETTY_FUNCTION__, up->sg_str, source_str);
|
||||||
__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;
|
|
||||||
pim_find_or_track_nexthop (&nht_p, up, NULL);
|
|
||||||
}
|
}
|
||||||
|
/* 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;
|
||||||
|
|
||||||
if (pim_nexthop_lookup(&rpf->source_nexthop,
|
src.family = AF_INET;
|
||||||
up->upstream_addr,
|
src.prefixlen = IPV4_MAX_BITLEN;
|
||||||
!PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) &&
|
src.u.prefix4 = up->upstream_addr; //RP or Src address
|
||||||
!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags))) {
|
grp.family = AF_INET;
|
||||||
return PIM_RPF_FAILURE;
|
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 (pnc.nexthop_num)
|
||||||
|
{
|
||||||
|
//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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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.family = AF_INET;
|
||||||
rpf->rpf_addr.u.prefix4 = pim_rpf_find_rpf_addr(up);
|
rpf->rpf_addr.u.prefix4 = pim_rpf_find_rpf_addr(up);
|
||||||
|
@ -94,6 +94,7 @@ uint8_t *pim_tlv_append_uint32(uint8_t *buf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
|
#define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
|
||||||
|
#define ucast_ipv6_encoding_len (2 + sizeof(struct in6_addr))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* An Encoded-Unicast address takes the following format:
|
* An Encoded-Unicast address takes the following format:
|
||||||
@ -135,6 +136,14 @@ pim_encode_addr_ucast (uint8_t *buf, struct prefix *p)
|
|||||||
memcpy (buf, &p->u.prefix4, sizeof (struct in_addr));
|
memcpy (buf, &p->u.prefix4, sizeof (struct in_addr));
|
||||||
return ucast_ipv4_encoding_len;
|
return ucast_ipv4_encoding_len;
|
||||||
break;
|
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:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
@ -216,12 +225,13 @@ pim_encode_addr_group (uint8_t *buf, afi_t afi, int bidir, int scope, struct in_
|
|||||||
|
|
||||||
uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
|
uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
|
||||||
const uint8_t *buf_pastend,
|
const uint8_t *buf_pastend,
|
||||||
struct list *ifconnected)
|
struct list *ifconnected,
|
||||||
|
int family)
|
||||||
{
|
{
|
||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
uint16_t option_len = 0;
|
uint16_t option_len = 0;
|
||||||
|
|
||||||
uint8_t *curr;
|
uint8_t *curr;
|
||||||
|
size_t uel;
|
||||||
|
|
||||||
node = listhead(ifconnected);
|
node = listhead(ifconnected);
|
||||||
|
|
||||||
@ -230,8 +240,10 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip first address (primary) */
|
if (family == AF_INET)
|
||||||
node = listnextnode(node);
|
uel = ucast_ipv4_encoding_len;
|
||||||
|
else
|
||||||
|
uel = ucast_ipv6_encoding_len;
|
||||||
|
|
||||||
/* Scan secondary address list */
|
/* Scan secondary address list */
|
||||||
curr = buf + 4; /* skip T and L */
|
curr = buf + 4; /* skip T and L */
|
||||||
@ -240,8 +252,14 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
|
|||||||
struct prefix *p = ifc->address;
|
struct prefix *p = ifc->address;
|
||||||
int l_encode;
|
int l_encode;
|
||||||
|
|
||||||
if ((curr + ucast_ipv4_encoding_len) > buf_pastend)
|
if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
|
||||||
return 0;
|
continue;
|
||||||
|
|
||||||
|
if ((curr + uel) > buf_pastend)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (p->family != family)
|
||||||
|
continue;
|
||||||
|
|
||||||
l_encode = pim_encode_addr_ucast (curr, p);
|
l_encode = pim_encode_addr_ucast (curr, p);
|
||||||
curr += l_encode;
|
curr += l_encode;
|
||||||
@ -251,7 +269,7 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
|
|||||||
if (PIM_DEBUG_PIM_TRACE_DETAIL) {
|
if (PIM_DEBUG_PIM_TRACE_DETAIL) {
|
||||||
zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu",
|
zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu",
|
||||||
__PRETTY_FUNCTION__,
|
__PRETTY_FUNCTION__,
|
||||||
option_len / ucast_ipv4_encoding_len);
|
option_len / uel);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (option_len < 1) {
|
if (option_len < 1) {
|
||||||
@ -491,9 +509,23 @@ pim_parse_addr_ucast (struct prefix *p,
|
|||||||
|
|
||||||
p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
|
p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
|
||||||
memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
|
memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
|
||||||
|
p->prefixlen = IPV4_MAX_PREFIXLEN;
|
||||||
addr += sizeof(struct in_addr);
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@ -706,6 +738,8 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
|
|||||||
addr_str, src_str, ifname);
|
addr_str, src_str, ifname);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
char src_str[INET_ADDRSTRLEN];
|
char src_str[INET_ADDRSTRLEN];
|
||||||
@ -759,8 +793,7 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
|
|||||||
FREE_ADDR_LIST(*hello_option_addr_list);
|
FREE_ADDR_LIST(*hello_option_addr_list);
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
p->family = tmp.family;
|
prefix_copy(p, &tmp);
|
||||||
p->u.prefix4 = tmp.u.prefix4;
|
|
||||||
listnode_add(*hello_option_addr_list, p);
|
listnode_add(*hello_option_addr_list, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,8 @@ uint8_t *pim_tlv_append_uint32(uint8_t *buf,
|
|||||||
uint32_t option_value);
|
uint32_t option_value);
|
||||||
uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
|
uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
|
||||||
const uint8_t *buf_pastend,
|
const uint8_t *buf_pastend,
|
||||||
struct list *ifconnected);
|
struct list *ifconnected,
|
||||||
|
int family);
|
||||||
|
|
||||||
int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr,
|
int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr,
|
||||||
pim_hello_options *hello_options,
|
pim_hello_options *hello_options,
|
||||||
|
@ -198,7 +198,20 @@ pim_upstream_del(struct pim_upstream *up, const char *name)
|
|||||||
upstream_channel_oil_detach(up);
|
upstream_channel_oil_detach(up);
|
||||||
|
|
||||||
if (up->sources)
|
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;
|
up->sources = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -227,8 +240,8 @@ pim_upstream_del(struct pim_upstream *up, const char *name)
|
|||||||
{
|
{
|
||||||
char buf[PREFIX2STR_BUFFER];
|
char buf[PREFIX2STR_BUFFER];
|
||||||
prefix2str (&nht_p, buf, sizeof (buf));
|
prefix2str (&nht_p, buf, sizeof (buf));
|
||||||
zlog_debug ("%s: Deregister upstream %s upstream addr %s with NHT ",
|
zlog_debug ("%s: Deregister upstream %s addr %s with Zebra",
|
||||||
__PRETTY_FUNCTION__, up->sg_str, buf);
|
__PRETTY_FUNCTION__, up->sg_str, buf);
|
||||||
}
|
}
|
||||||
pim_delete_tracked_nexthop (&nht_p, up, NULL);
|
pim_delete_tracked_nexthop (&nht_p, up, NULL);
|
||||||
|
|
||||||
@ -694,10 +707,12 @@ pim_upstream_new (struct prefix_sg *sg,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pim_ifp = up->rpf.source_nexthop.interface->info;
|
if (up->rpf.source_nexthop.interface)
|
||||||
if (pim_ifp)
|
{
|
||||||
up->channel_oil = pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index);
|
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);
|
listnode_add_sort(pim_upstream_list, up);
|
||||||
|
|
||||||
if (PIM_DEBUG_TRACE)
|
if (PIM_DEBUG_TRACE)
|
||||||
@ -768,10 +783,14 @@ struct pim_upstream *pim_upstream_add(struct prefix_sg *sg,
|
|||||||
if (PIM_DEBUG_TRACE)
|
if (PIM_DEBUG_TRACE)
|
||||||
{
|
{
|
||||||
if (up)
|
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,
|
__PRETTY_FUNCTION__, name,
|
||||||
up->sg_str, found,
|
up->sg_str, buf, found,
|
||||||
up->ref_count);
|
up->ref_count);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
zlog_debug("%s(%s): (%s) failure to create",
|
zlog_debug("%s(%s): (%s) failure to create",
|
||||||
__PRETTY_FUNCTION__, name,
|
__PRETTY_FUNCTION__, name,
|
||||||
@ -1083,26 +1102,31 @@ pim_upstream_keep_alive_timer (struct thread *t)
|
|||||||
up->t_ka_timer = NULL;
|
up->t_ka_timer = NULL;
|
||||||
|
|
||||||
if (I_am_RP (up->sg.grp))
|
if (I_am_RP (up->sg.grp))
|
||||||
{
|
{
|
||||||
pim_br_clear_pmbr (&up->sg);
|
pim_br_clear_pmbr (&up->sg);
|
||||||
/*
|
/*
|
||||||
* We need to do more here :)
|
* We need to do more here :)
|
||||||
* But this is the start.
|
* But this is the start.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/* source is no longer active - pull the SA from MSDP's cache */
|
/* source is no longer active - pull the SA from MSDP's cache */
|
||||||
pim_msdp_sa_local_del(&up->sg);
|
pim_msdp_sa_local_del(&up->sg);
|
||||||
|
|
||||||
/* if entry was created because of activity we need to deref it */
|
/* if entry was created because of activity we need to deref it */
|
||||||
if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
|
if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
|
||||||
{
|
{
|
||||||
pim_upstream_fhr_kat_expiry(up);
|
pim_upstream_fhr_kat_expiry(up);
|
||||||
if (PIM_DEBUG_TRACE)
|
if (PIM_DEBUG_TRACE)
|
||||||
zlog_debug ("kat expired on %s; remove stream reference", up->sg_str);
|
zlog_debug ("kat expired on %s; remove stream reference", up->sg_str);
|
||||||
PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
|
PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
|
||||||
pim_upstream_del(up, __PRETTY_FUNCTION__);
|
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 0;
|
||||||
}
|
}
|
||||||
@ -1633,28 +1657,67 @@ pim_upstream_sg_running (void *arg)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pim_upstream_kat_start_ok(up)) {
|
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_DEBUG_TRACE)
|
/* Add a source reference to the stream if
|
||||||
zlog_debug ("source reference created on kat restart %s", up->sg_str);
|
* 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_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM);
|
||||||
PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
|
PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
|
||||||
pim_upstream_fhr_kat_start(up);
|
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);
|
pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
|
||||||
}
|
|
||||||
|
|
||||||
if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE)
|
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;
|
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
|
void
|
||||||
pim_upstream_init (void)
|
pim_upstream_init (void)
|
||||||
{
|
{
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
#define PIM_UPSTREAM_FLAG_MASK_SRC_STREAM (1 << 5)
|
#define PIM_UPSTREAM_FLAG_MASK_SRC_STREAM (1 << 5)
|
||||||
#define PIM_UPSTREAM_FLAG_MASK_SRC_MSDP (1 << 6)
|
#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_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(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
|
||||||
#define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
|
#define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
|
||||||
@ -43,6 +45,7 @@
|
|||||||
#define PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
|
#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_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_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(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
|
||||||
#define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
|
#define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
|
||||||
@ -52,6 +55,7 @@
|
|||||||
#define PIM_UPSTREAM_FLAG_SET_SRC_STREAM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
|
#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_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_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(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
|
||||||
#define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
|
#define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
|
||||||
@ -61,6 +65,7 @@
|
|||||||
#define PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
|
#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_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_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 {
|
enum pim_upstream_state {
|
||||||
PIM_UPSTREAM_NOTJOINED,
|
PIM_UPSTREAM_NOTJOINED,
|
||||||
@ -193,4 +198,7 @@ void pim_upstream_terminate (void);
|
|||||||
void join_timer_start (struct pim_upstream *up);
|
void join_timer_start (struct pim_upstream *up);
|
||||||
int pim_upstream_compare (void *arg1, void *arg2);
|
int pim_upstream_compare (void *arg1, void *arg2);
|
||||||
void pim_upstream_register_reevaluate (void);
|
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 */
|
#endif /* PIM_UPSTREAM_H */
|
||||||
|
@ -150,6 +150,12 @@ int pim_global_config_write(struct vty *vty)
|
|||||||
|
|
||||||
writes += pim_msdp_config_write (vty);
|
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);
|
writes += pim_rp_config_write (vty);
|
||||||
|
|
||||||
if (qpim_register_suppress_time != PIM_REGISTER_SUPPRESSION_TIME_DEFAULT)
|
if (qpim_register_suppress_time != PIM_REGISTER_SUPPRESSION_TIME_DEFAULT)
|
||||||
@ -182,6 +188,12 @@ int pim_global_config_write(struct vty *vty)
|
|||||||
ssm->plist_name, VTY_NEWLINE);
|
ssm->plist_name, VTY_NEWLINE);
|
||||||
++writes;
|
++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) {
|
if (qpim_ssmpingd_list) {
|
||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
|
188
pimd/pim_zebra.c
188
pimd/pim_zebra.c
@ -258,31 +258,11 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
|
|||||||
#endif
|
#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)) {
|
if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
|
||||||
/* trying to add primary address */
|
/* trying to add primary address */
|
||||||
|
|
||||||
struct in_addr primary_addr = pim_find_primary_addr(c->ifp);
|
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) {
|
if (PIM_DEBUG_ZEBRA) {
|
||||||
/* but we had a primary address already */
|
/* but we had a primary address already */
|
||||||
|
|
||||||
@ -372,6 +352,12 @@ static void scan_upstream_rpf_cache()
|
|||||||
for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
|
for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
|
||||||
enum pim_rpf_result rpf_result;
|
enum pim_rpf_result rpf_result;
|
||||||
struct pim_rpf old;
|
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.interface = up->rpf.source_nexthop.interface;
|
||||||
old.source_nexthop.nbr = up->rpf.source_nexthop.nbr;
|
old.source_nexthop.nbr = up->rpf.source_nexthop.nbr;
|
||||||
@ -574,7 +560,8 @@ static int on_rpf_cache_refresh(struct thread *t)
|
|||||||
qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
|
qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
|
||||||
++qpim_rpf_cache_refresh_events;
|
++qpim_rpf_cache_refresh_events;
|
||||||
|
|
||||||
pim_rp_setup ();
|
//It is called as part of pim_neighbor_add
|
||||||
|
//pim_rp_setup ();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -836,6 +823,7 @@ void igmp_source_forward_start(struct igmp_source *source)
|
|||||||
struct igmp_group *group;
|
struct igmp_group *group;
|
||||||
struct prefix_sg sg;
|
struct prefix_sg sg;
|
||||||
int result;
|
int result;
|
||||||
|
int input_iface_vif_index = 0;
|
||||||
|
|
||||||
memset (&sg, 0, sizeof (struct prefix_sg));
|
memset (&sg, 0, sizeof (struct prefix_sg));
|
||||||
sg.src = source->source_addr;
|
sg.src = source->source_addr;
|
||||||
@ -861,11 +849,61 @@ void igmp_source_forward_start(struct igmp_source *source)
|
|||||||
if (!source->source_channel_oil) {
|
if (!source->source_channel_oil) {
|
||||||
struct in_addr vif_source;
|
struct in_addr vif_source;
|
||||||
struct pim_interface *pim_oif;
|
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))
|
if (!pim_rp_set_upstream_addr (&vif_source, source->source_addr, sg.grp))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int input_iface_vif_index = fib_lookup_if_vif_index(vif_source);
|
/* 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 (input_iface_vif_index < 1) {
|
||||||
if (PIM_DEBUG_IGMP_TRACE)
|
if (PIM_DEBUG_IGMP_TRACE)
|
||||||
{
|
{
|
||||||
@ -1013,6 +1051,7 @@ void pim_forward_start(struct pim_ifchannel *ch)
|
|||||||
{
|
{
|
||||||
struct pim_upstream *up = ch->upstream;
|
struct pim_upstream *up = ch->upstream;
|
||||||
uint32_t mask = PIM_OIF_FLAG_PROTO_PIM;
|
uint32_t mask = PIM_OIF_FLAG_PROTO_PIM;
|
||||||
|
int input_iface_vif_index = 0;
|
||||||
|
|
||||||
if (PIM_DEBUG_PIM_TRACE) {
|
if (PIM_DEBUG_PIM_TRACE) {
|
||||||
char source_str[INET_ADDRSTRLEN];
|
char source_str[INET_ADDRSTRLEN];
|
||||||
@ -1022,40 +1061,95 @@ void pim_forward_start(struct pim_ifchannel *ch)
|
|||||||
pim_inet4_dump("<source?>", ch->sg.src, source_str, sizeof(source_str));
|
pim_inet4_dump("<source?>", ch->sg.src, source_str, sizeof(source_str));
|
||||||
pim_inet4_dump("<group?>", ch->sg.grp, group_str, sizeof(group_str));
|
pim_inet4_dump("<group?>", ch->sg.grp, group_str, sizeof(group_str));
|
||||||
pim_inet4_dump("<upstream?>", up->upstream_addr, upstream_str, sizeof(upstream_str));
|
pim_inet4_dump("<upstream?>", up->upstream_addr, upstream_str, sizeof(upstream_str));
|
||||||
zlog_debug("%s: (S,G)=(%s,%s) oif=%s(%s)",
|
zlog_debug("%s: (S,G)=(%s,%s) oif=%s (%s)",
|
||||||
__PRETTY_FUNCTION__,
|
__PRETTY_FUNCTION__,
|
||||||
source_str, group_str, ch->interface->name, upstream_str);
|
source_str, group_str, ch->interface->name, upstream_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!up->channel_oil) {
|
/* Resolve IIF for upstream as mroute_del sets mfcc_parent to MAXVIFS,
|
||||||
int input_iface_vif_index = fib_lookup_if_vif_index(up->upstream_addr);
|
as part of mroute_del called by pim_forward_stop.
|
||||||
if (input_iface_vif_index < 1) {
|
*/
|
||||||
if (PIM_DEBUG_PIM_TRACE)
|
if (!up->channel_oil ||
|
||||||
{
|
(up->channel_oil && up->channel_oil->oil.mfcc_parent >= MAXVIFS))
|
||||||
char source_str[INET_ADDRSTRLEN];
|
{
|
||||||
pim_inet4_dump("<source?>", up->sg.src, source_str, sizeof(source_str));
|
struct prefix nht_p, src, grp;
|
||||||
zlog_debug("%s %s: could not find input interface for source %s",
|
int ret = 0;
|
||||||
__FILE__, __PRETTY_FUNCTION__,
|
struct pim_nexthop_cache out_pnc;
|
||||||
source_str);
|
struct pim_nexthop nexthop;
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
up->channel_oil = pim_channel_oil_add(&up->sg,
|
/* Register addr with Zebra NHT */
|
||||||
input_iface_vif_index);
|
nht_p.family = AF_INET;
|
||||||
if (!up->channel_oil) {
|
nht_p.prefixlen = IPV4_MAX_BITLEN;
|
||||||
if (PIM_DEBUG_PIM_TRACE)
|
nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
|
||||||
zlog_debug("%s %s: could not create OIL for channel (S,G)=%s",
|
grp.family = AF_INET;
|
||||||
__FILE__, __PRETTY_FUNCTION__,
|
grp.prefixlen = IPV4_MAX_BITLEN;
|
||||||
up->sg_str);
|
grp.u.prefix4 = up->sg.grp;
|
||||||
return;
|
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);
|
||||||
|
|
||||||
|
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)
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
|
||||||
mask = PIM_OIF_FLAG_PROTO_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)
|
void pim_forward_stop(struct pim_ifchannel *ch)
|
||||||
|
@ -222,6 +222,7 @@ static int zclient_read_nexthop(struct zclient *zlookup,
|
|||||||
for (i = 0; i < nexthop_num; ++i) {
|
for (i = 0; i < nexthop_num; ++i) {
|
||||||
enum nexthop_types_t nexthop_type;
|
enum nexthop_types_t nexthop_type;
|
||||||
struct pim_neighbor *nbr;
|
struct pim_neighbor *nbr;
|
||||||
|
struct prefix p;
|
||||||
|
|
||||||
nexthop_type = stream_getc(s);
|
nexthop_type = stream_getc(s);
|
||||||
if (num_ifindex >= tab_size) {
|
if (num_ifindex >= tab_size) {
|
||||||
@ -251,9 +252,24 @@ static int zclient_read_nexthop(struct zclient *zlookup,
|
|||||||
break;
|
break;
|
||||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||||
nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET6;
|
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);
|
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)
|
if (nbr)
|
||||||
{
|
{
|
||||||
nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET;
|
nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET;
|
||||||
|
10
pimd/pimd.c
10
pimd/pimd.c
@ -75,7 +75,9 @@ unsigned int qpim_keep_alive_time = PIM_KEEPALIVE_PERIOD;
|
|||||||
signed int qpim_rp_keep_alive_time = 0;
|
signed int qpim_rp_keep_alive_time = 0;
|
||||||
int64_t qpim_nexthop_lookups = 0;
|
int64_t qpim_nexthop_lookups = 0;
|
||||||
int qpim_packet_process = PIM_DEFAULT_PACKET_PROCESS;
|
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_suppress_time = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT;
|
||||||
int32_t qpim_register_probe_time = PIM_REGISTER_PROBE_TIME_DEFAULT;
|
int32_t qpim_register_probe_time = PIM_REGISTER_PROBE_TIME_DEFAULT;
|
||||||
@ -115,7 +117,10 @@ pim_vrf_enable (struct vrf *vrf)
|
|||||||
* We will crash and burn otherwise
|
* We will crash and burn otherwise
|
||||||
*/
|
*/
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pimg->send_v6_secondary = 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -249,6 +254,7 @@ pim_instance_init (vrf_id_t vrf_id, afi_t afi)
|
|||||||
pim->vrf_id = vrf_id;
|
pim->vrf_id = vrf_id;
|
||||||
pim->afi = afi;
|
pim->afi = afi;
|
||||||
|
|
||||||
|
pim->spt_switchover = PIM_SPT_IMMEDIATE;
|
||||||
pim->rpf_hash = hash_create_size (256, pim_rpf_hash_key, pim_rpf_equal);
|
pim->rpf_hash = hash_create_size (256, pim_rpf_hash_key, pim_rpf_equal);
|
||||||
|
|
||||||
if (PIM_DEBUG_ZEBRA)
|
if (PIM_DEBUG_ZEBRA)
|
||||||
|
14
pimd/pimd.h
14
pimd/pimd.h
@ -155,6 +155,9 @@ struct list *qpim_static_route_list; /* list of routes added static
|
|||||||
extern unsigned int qpim_keep_alive_time;
|
extern unsigned int qpim_keep_alive_time;
|
||||||
extern signed int qpim_rp_keep_alive_time;
|
extern signed int qpim_rp_keep_alive_time;
|
||||||
extern int qpim_packet_process;
|
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_DEFAULT_PACKET_PROCESS 3
|
||||||
|
|
||||||
#define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2)
|
#define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2)
|
||||||
@ -237,13 +240,24 @@ extern int32_t qpim_register_probe_time;
|
|||||||
#define PIM_DONT_DEBUG_MSDP_PACKETS (qpim_debugs &= ~PIM_MASK_MSDP_PACKETS)
|
#define PIM_DONT_DEBUG_MSDP_PACKETS (qpim_debugs &= ~PIM_MASK_MSDP_PACKETS)
|
||||||
#define PIM_DONT_DEBUG_MSDP_INTERNAL (qpim_debugs &= ~PIM_MASK_MSDP_INTERNAL)
|
#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 */
|
/* Per VRF PIM DB */
|
||||||
struct pim_instance
|
struct pim_instance
|
||||||
{
|
{
|
||||||
afi_t afi;
|
afi_t afi;
|
||||||
vrf_id_t vrf_id;
|
vrf_id_t vrf_id;
|
||||||
|
|
||||||
|
enum pim_spt_switchover spt_switchover;
|
||||||
|
|
||||||
struct hash *rpf_hash;
|
struct hash *rpf_hash;
|
||||||
|
|
||||||
void *ssm_info; /* per-vrf SSM configuration */
|
void *ssm_info; /* per-vrf SSM configuration */
|
||||||
|
|
||||||
|
int send_v6_secondary;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct pim_instance *pimg; //Pim Global Instance
|
extern struct pim_instance *pimg; //Pim Global Instance
|
||||||
|
@ -339,7 +339,7 @@ DEFUN (rip_redistribute_type,
|
|||||||
|
|
||||||
for(i = 0; redist_type[i].str; i++)
|
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)
|
redist_type[i].str_min_len) == 0)
|
||||||
{
|
{
|
||||||
zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient,
|
zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient,
|
||||||
@ -348,7 +348,7 @@ DEFUN (rip_redistribute_type,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vty_out(vty, "Invalid type %s%s", argv[2]->arg,
|
vty_out(vty, "Invalid type %s%s", argv[1]->arg,
|
||||||
VTY_NEWLINE);
|
VTY_NEWLINE);
|
||||||
|
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
@ -365,7 +365,7 @@ DEFUN (no_rip_redistribute_type,
|
|||||||
|
|
||||||
for (i = 0; redist_type[i].str; i++)
|
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)
|
redist_type[i].str_min_len) == 0)
|
||||||
{
|
{
|
||||||
rip_metric_unset (redist_type[i].type, DONT_CARE_METRIC_RIP);
|
rip_metric_unset (redist_type[i].type, DONT_CARE_METRIC_RIP);
|
||||||
@ -375,7 +375,7 @@ DEFUN (no_rip_redistribute_type,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vty_out(vty, "Invalid type %s%s", argv[3]->arg,
|
vty_out(vty, "Invalid type %s%s", argv[2]->arg,
|
||||||
VTY_NEWLINE);
|
VTY_NEWLINE);
|
||||||
|
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
|
@ -1242,9 +1242,7 @@ DEFUNSH (VTYSH_BGPD,
|
|||||||
"Layer2 VPN Address family\n"
|
"Layer2 VPN Address family\n"
|
||||||
"Ethernet Virtual Private Network Subsequent Address Family\n")
|
"Ethernet Virtual Private Network Subsequent Address Family\n")
|
||||||
{
|
{
|
||||||
#if defined(HAVE_EVPN)
|
|
||||||
vty->node = BGP_EVPN_NODE;
|
vty->node = BGP_EVPN_NODE;
|
||||||
#endif /* HAVE_EVPN */
|
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user