diff --git a/README b/README index a0aa895367..7c6ef7034e 100644 --- a/README +++ b/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. -Currently Free Range Routing supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, +Currently FRRouting supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, RIPv2, RIPng, PIM-SM/MSDP and LDP as well as very early support for IS-IS. See the file REPORTING-BUGS to report bugs. -Free Range Routing is free software. See the file COPYING for copying conditions. +Free RRRouting is free software. See the file COPYING for copying conditions. -Public email discussion can be found at https://lists.nox.tf/listinfo/frr +Public email discussion can be found at https://lists.frrouting.org/listinfo -Our public slack channel is at https://freerangerouting.slack.com +Our public slack channel is at https://frrouting.slack.com diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index be97ffda69..5b24d4ec61 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -1,20 +1,20 @@ /* Ethernet-VPN Attribute handling file Copyright (C) 2016 6WIND -This file is part of Free Range Routing. +This file is part of FRRouting. -Free Range Routing is free software; you can redistribute it and/or modify it +FRRouting is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. -Free Range Routing is distributed in the hope that it will be useful, but +FRRouting is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with Free Range Routing; see the file COPYING. If not, write to the Free +along with FRRouting; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index e6da7e7080..4b7d24de18 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -1,20 +1,20 @@ /* E-VPN attribute handling structure file Copyright (C) 2016 6WIND -This file is part of Free Range Routing. +This file is part of FRRouting. -Free Range Routing is free software; you can redistribute it and/or modify it +FRRouting is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. -Free Range Routing is distributed in the hope that it will be useful, but +FRRouting is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with Free Range Routing; see the file COPYING. If not, write to the Free +along with FRRouting; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 1ab8e23236..612f49f1cb 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1,20 +1,20 @@ /* Ethernet-VPN Packet and vty Processing File Copyright (C) 2016 6WIND -This file is part of Free Range Routing. +This file is part of FRRouting. -Free Range Routing is free software; you can redistribute it and/or modify it +FRRouting is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. -Free Range Routing is distributed in the hope that it will be useful, but +FRRouting is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with Free Range Routing; see the file COPYING. If not, write to the Free +along with FRRouting; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 63c1a766ea..9b24bb066a 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -1,20 +1,20 @@ /* E-VPN header for packet handling Copyright (C) 2016 6WIND -This file is part of Free Range Routing. +This file is part of FRRouting. -Free Range Routing is free software; you can redistribute it and/or modify it +FRRouting is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. -Free Range Routing is distributed in the hope that it will be useful, but +FRRouting is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with Free Range Routing; see the file COPYING. If not, write to the Free +along with FRRouting; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 1654265a72..97ce7ee969 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -1,20 +1,20 @@ /* Ethernet-VPN Packet and vty Processing File Copyright (C) 2017 6WIND -This file is part of Free Range Routing +This file is part of FRRouting -Free Range Routing is free software; you can redistribute it and/or modify it +FRRouting is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. -Free Range Routing is distributed in the hope that it will be useful, but +FRRouting is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with Free Range Routing; see the file COPYING. If not, write to the Free +along with FRRouting; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ diff --git a/bgpd/bgp_evpn_vty.h b/bgpd/bgp_evpn_vty.h index 11e93a5281..68b5f5cfbf 100644 --- a/bgpd/bgp_evpn_vty.h +++ b/bgpd/bgp_evpn_vty.h @@ -1,20 +1,20 @@ /* EVPN VTY functions to EVPN Copyright (C) 2017 6WIND -This file is part of Free Range Routing. +This file is part of FRRouting. -Free Range Routing is free software; you can redistribute it and/or modify it +FRRouting is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. -Free Range Routing is distributed in the hope that it will be useful, but +FRRouting is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with Free Range Routing; see the file COPYING. If not, write to the Free +along with FRRouting; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 152d4a7acd..3b844cf70e 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -66,6 +66,7 @@ static const struct option longopts[] = { "listenon", required_argument, NULL, 'l'}, { "retain", no_argument, NULL, 'r'}, { "no_kernel", no_argument, NULL, 'n'}, + { "skip_runas", no_argument, NULL, 'S'}, { "ecmp", required_argument, NULL, 'e'}, { 0 } }; @@ -151,7 +152,8 @@ sigint (void) if (! retain_mode) { bgp_terminate (); - zprivs_terminate (&bgpd_privs); + if (bgpd_privs.user) /* NULL if skip_runas flag set */ + zprivs_terminate (&bgpd_privs); } bgp_exit (0); @@ -365,6 +367,8 @@ main (int argc, char **argv) int bgp_port = BGP_PORT_DEFAULT; char *bgp_address = NULL; + int no_fib_flag = 0; + int skip_runas = 0; frr_preinit(&bgpd_di, argc, argv); frr_opt_add("p:l:rne:", longopts, @@ -372,6 +376,7 @@ main (int argc, char **argv) " -l, --listenon Listen on specified address (implies -n)\n" " -r, --retain When program terminates, retain added route by bgpd.\n" " -n, --no_kernel Do not install route to kernel.\n" + " -S, --skip_runas Skip capabilities checks, and changing user and group IDs.\n" " -e, --ecmp Specify ECMP to use.\n"); /* Command line argument treatment. */ @@ -391,7 +396,7 @@ main (int argc, char **argv) if (tmp_port <= 0 || tmp_port > 0xffff) bgp_port = BGP_PORT_DEFAULT; else - bm->port = tmp_port; + bgp_port = tmp_port; break; case 'e': multipath_num = atoi (optarg); @@ -408,18 +413,25 @@ main (int argc, char **argv) bgp_address = optarg; /* listenon implies -n */ case 'n': - bgp_option_set (BGP_OPT_NO_FIB); + no_fib_flag = 1; + break; + case 'S': + skip_runas = 1; break; default: frr_help_exit (1); break; } } + if (skip_runas) + memset (&bgpd_privs, 0, sizeof (bgpd_privs)); /* BGP master init. */ bgp_master_init (frr_init ()); bm->port = bgp_port; bm->address = bgp_address; + if (no_fib_flag) + bgp_option_set (BGP_OPT_NO_FIB); /* Initializations. */ bgp_vrf_init (); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 05e34b4375..140003cef0 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -8424,7 +8424,7 @@ bgp_show_lcommunity (struct vty *vty, struct bgp *bgp, int argc, buffer_putc (b, ' '); else { - if (strmatch (argv[i]->text, "")) + if (strmatch (argv[i]->text, "AA:BB:CC")) { first = 1; 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); if (! lcom) { - vty_out (vty, "%% Large-community malformed: %s", VTY_NEWLINE); + vty_out (vty, "%% Large-community malformed%s", VTY_NEWLINE); return CMD_WARNING; } @@ -8554,8 +8554,7 @@ DEFUN (show_ip_bgp_large_community, return CMD_WARNING; } - argv_find (argv, argc, "large-community", &idx); - if (strmatch(argv[idx+1]->text, "AA:BB:CC")) + if (argv_find (argv, argc, "AA:BB:CC", &idx)) return bgp_show_lcommunity (vty, bgp, argc, argv, afi, safi, uj); else return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_all, NULL, uj); @@ -8818,8 +8817,6 @@ static int bgp_show_regexp (struct vty *vty, const char *regstr, afi_t afi, safi_t safi, enum bgp_show_type type) { - return CMD_SUCCESS; - regex_t *regex; int rc; diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index bafc81eaf8..9b5a7a5ebb 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1437,7 +1437,7 @@ route_set_aspath_prepend_compile (const char *arg) { unsigned int num; - if (sscanf(arg, "last-as %u", &num) == 1 && num > 0 && num < 10) + if (sscanf(arg, "last-as %u", &num) == 1 && num > 0 && num <= 10) return (void*)(uintptr_t)num; return route_aspath_compile(arg); @@ -3677,12 +3677,12 @@ DEFUN (set_aspath_prepend_asn, DEFUN (set_aspath_prepend_lastas, set_aspath_prepend_lastas_cmd, - "set as-path prepend last-as (1-9)", + "set as-path prepend last-as (1-10)", SET_STR "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n" "Use the peer's AS-number\n" - "Number of times to insert") + "Number of times to insert\n") { return set_aspath_prepend_asn (self, vty, argc, argv); } diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c index edc5891d22..5b1b1b85b2 100644 --- a/bgpd/bgp_vpn.c +++ b/bgpd/bgp_vpn.c @@ -1,20 +1,20 @@ /* VPN Related functions Copyright (C) 2017 6WIND -This file is part of Free Range Routing +This file is part of FRRouting -Free Range Routing is free software; you can redistribute it and/or modify it +FRRouting is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. -Free Range Routing is distributed in the hope that it will be useful, but +FRRouting is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with Free Range Routing; see the file COPYING. If not, write to the Free +along with FRRouting; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ diff --git a/bgpd/bgp_vpn.h b/bgpd/bgp_vpn.h index a16914b65e..dd53503bf3 100644 --- a/bgpd/bgp_vpn.h +++ b/bgpd/bgp_vpn.h @@ -1,20 +1,20 @@ /* VPN common functions to MP-BGP Copyright (C) 2017 6WIND -This file is part of Free Range Routing. +This file is part of FRRouting. -Free Range Routing is free software; you can redistribute it and/or modify it +FRRouting is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. -Free Range Routing is distributed in the hope that it will be useful, but +FRRouting is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with Free Range Routing; see the file COPYING. If not, write to the Free +along with FRRouting; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ diff --git a/configure.ac b/configure.ac index 2c9f64a4fe..bef74c7267 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.60) -AC_INIT(frr, 2.1-dev, [https://github.com/frrouting/frr/issues]) +AC_INIT(frr, 3.1-dev, [https://github.com/frrouting/frr/issues]) PACKAGE_URL="https://frrouting.org/" PACKAGE_FULLNAME="FRRouting" AC_SUBST(PACKAGE_FULLNAME) diff --git a/debian/changelog b/debian/changelog index 8302af4b4c..4ea86929fc 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,30 @@ +frr (3.1-dev) Released; urgency=medium + + * New Enabled: PIM draft Unnumbered + + -- frr 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 Wed, 5 Apr 2017 22:23:42 -0500 + frr (2.1) Released; urgency=medium * Switchover to FRR diff --git a/doc/install.texi b/doc/install.texi index b34f316844..d989928b8f 100644 --- a/doc/install.texi +++ b/doc/install.texi @@ -218,18 +218,14 @@ routing utility. It contains @command{ifconfig}, @command{route}, After configuring the software, you will need to compile it for your system. Simply issue the command @command{make} in the root of the source -directory and the software will be compiled. If you have *any* problems -at this stage, be certain to send a bug report @xref{Bug Reports}. +directory and the software will be compiled. Cliff Note versions of +different compilation examples can be found in the doc/Building_FRR_on_XXX.md +files. If you have *any* problems at this stage, be certain to send a +bug report @xref{Bug Reports}. @example -% ./configure -. -. -. -./configure output -. -. -. +% ./bootstrap.sh +% ./configure % make @end example @c A - End of node, Building the Software diff --git a/lib/command_lex.l b/lib/command_lex.l index deec1757c2..c020d193a1 100644 --- a/lib/command_lex.l +++ b/lib/command_lex.l @@ -23,6 +23,9 @@ */ %{ +/* ignore harmless bug in old versions of flex */ +#pragma GCC diagnostic ignored "-Wsign-compare" + #include "command_parse.h" #define YY_USER_ACTION yylloc->last_column += yyleng; diff --git a/lib/distribute.c b/lib/distribute.c index 01c338f177..f85994c9a8 100644 --- a/lib/distribute.c +++ b/lib/distribute.c @@ -254,6 +254,7 @@ DEFUN (distribute_list, distribute_list_cmd, "distribute-list [prefix] WORD [WORD]", "Filter networks in routing updates\n" + "Specify a prefix\n" "Access-list name\n" "Filter incoming routing updates\n" "Filter outgoing routing updates\n" @@ -316,7 +317,9 @@ DEFUN (no_distribute_list, no_distribute_list_cmd, "no [ipv6] distribute-list [prefix] WORD [WORD]", NO_STR + "IPv6\n" "Filter networks in routing updates\n" + "Specify a prefix\n" "Access-list name\n" "Filter incoming routing updates\n" "Filter outgoing routing updates\n" diff --git a/lib/pqueue.c b/lib/pqueue.c index 0f870564da..fa502b462a 100644 --- a/lib/pqueue.c +++ b/lib/pqueue.c @@ -188,3 +188,11 @@ pqueue_remove_at (int index, struct pqueue *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); +} diff --git a/lib/pqueue.h b/lib/pqueue.h index 8bb6961d86..b39fb92ee9 100644 --- a/lib/pqueue.h +++ b/lib/pqueue.h @@ -39,6 +39,7 @@ extern void pqueue_delete (struct pqueue *queue); extern void pqueue_enqueue (void *data, struct pqueue *queue); extern void *pqueue_dequeue (struct pqueue *queue); extern void pqueue_remove_at (int index, struct pqueue *queue); +extern void pqueue_remove (void *data, struct pqueue *queue); extern void trickle_down (int index, struct pqueue *queue); extern void trickle_up (int index, struct pqueue *queue); diff --git a/lib/privs.c b/lib/privs.c index decd4bb7db..767ab667e7 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -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 */ if ((ngroups) && (zprivs_state.zsuid != zprivs_state.zuid)) { diff --git a/lib/zclient.c b/lib/zclient.c index 541a5444cf..e3eadf22a4 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1531,7 +1531,9 @@ lm_label_manager_connect (struct zclient *zclient) vrf_id_t vrf_id; u_int16_t cmd; - zlog_debug ("Connecting to Label Manager"); + if (zclient_debug) + zlog_debug ("Connecting to Label Manager"); + if (zclient->sock < 0) return -1; @@ -1563,7 +1565,8 @@ lm_label_manager_connect (struct zclient *zclient) zclient->sock = -1; return -1; } - zlog_debug ("%s: Label manager connect request (%d bytes) sent", __func__, ret); + if (zclient_debug) + zlog_debug ("%s: Label manager connect request (%d bytes) sent", __func__, ret); /* read response */ s = zclient->ibuf; @@ -1577,8 +1580,9 @@ lm_label_manager_connect (struct zclient *zclient) } /* result */ result = stream_getc(s); - zlog_debug ("%s: Label Manager connect response (%d bytes) received, result %u", - __func__, size, result); + if (zclient_debug) + zlog_debug ("%s: Label Manager connect response (%d bytes) received, result %u", + __func__, size, result); return (int)result; } @@ -1609,7 +1613,9 @@ lm_get_label_chunk (struct zclient *zclient, u_char keep, uint32_t chunk_size, u_int16_t cmd; u_char response_keep; - zlog_debug ("Getting Label Chunk"); + if (zclient_debug) + zlog_debug ("Getting Label Chunk"); + if (zclient->sock < 0) return -1; @@ -1639,7 +1645,8 @@ lm_get_label_chunk (struct zclient *zclient, u_char keep, uint32_t chunk_size, zclient->sock = -1; return -1; } - zlog_debug ("%s: Label chunk request (%d bytes) sent", __func__, ret); + if (zclient_debug) + zlog_debug ("%s: Label chunk request (%d bytes) sent", __func__, ret); /* read response */ s = zclient->ibuf; @@ -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__); return -1; } - zlog_debug ("%s: Label chunk response (%d bytes) received", __func__, size); + if (zclient_debug) + zlog_debug ("%s: Label chunk response (%d bytes) received", __func__, size); + /* keep */ response_keep = stream_getc(s); /* start and end labels */ @@ -1672,8 +1681,9 @@ lm_get_label_chunk (struct zclient *zclient, u_char keep, uint32_t chunk_size, return -1; } - zlog_debug ("Label Chunk assign: %u - %u (%u) ", - *start, *end, response_keep); + if (zclient_debug) + zlog_debug ("Label Chunk assign: %u - %u (%u) ", + *start, *end, response_keep); return 0; } @@ -1692,7 +1702,9 @@ lm_release_label_chunk (struct zclient *zclient, uint32_t start, uint32_t end) int ret; struct stream *s; - zlog_debug ("Releasing Label Chunk"); + if (zclient_debug) + zlog_debug ("Releasing Label Chunk"); + if (zclient->sock < 0) return -1; diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 49474df826..b4c456e0aa 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -3557,7 +3557,7 @@ show_ip_ospf_interface_common (struct vty *vty, struct ospf *ospf, int argc, VTY_NEWLINE, VTY_NEWLINE); } - if (argc == (iface_argv + 1)) + if (argc == iface_argv) { /* Show All Interfaces.*/ for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) @@ -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 { /* Interface name is specified. */ @@ -3634,7 +3615,10 @@ DEFUN (show_ip_ospf_interface, if ((ospf = ospf_lookup()) == NULL || !ospf->oi_running) return CMD_SUCCESS; - return show_ip_ospf_interface_common(vty, ospf, argc, argv, 0, uj); + if (uj) + argc--; + + return show_ip_ospf_interface_common(vty, ospf, argc, argv, 4, uj); } DEFUN (show_ip_ospf_instance_interface, @@ -3657,7 +3641,10 @@ DEFUN (show_ip_ospf_instance_interface, if ((ospf = ospf_lookup_instance (instance)) == NULL || !ospf->oi_running) return CMD_SUCCESS; - return show_ip_ospf_interface_common(vty, ospf, argc, argv, 1, uj); + if (uj) + argc--; + + return show_ip_ospf_interface_common(vty, ospf, argc, argv, 5, uj); } static void diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 3c5a16ec68..53a080a3ab 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -26,6 +26,8 @@ #include "prefix.h" #include "zclient.h" #include "plist.h" +#include "hash.h" +#include "nexthop.h" #include "pimd.h" #include "pim_mroute.h" @@ -55,6 +57,7 @@ #include "pim_zlookup.h" #include "pim_msdp.h" #include "pim_ssm.h" +#include "pim_nht.h" static struct cmd_node pim_global_node = { PIM_NODE, @@ -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); if (uj) { + char pbuf[PREFIX2STR_BUFFER]; json_row = json_object_new_object(); 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(); 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); } @@ -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); } if (pim_ifp->sec_addr_list) { + char pbuf[PREFIX2STR_BUFFER]; vty_out(vty, "Address : %s (primary)%s", - inet_ntoa(ifaddr), VTY_NEWLINE); + inet_ntoa(ifaddr), VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, sec_node, sec_addr)) { vty_out(vty, " %s%s", - inet_ntoa(sec_addr->addr), VTY_NEWLINE); + prefix2str(&sec_addr->addr, + pbuf, + sizeof(pbuf)), VTY_NEWLINE); } } else { vty_out(vty, "Address : %s%s", inet_ntoa(ifaddr), VTY_NEWLINE); @@ -1040,6 +1050,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj) struct pim_upstream *up; int fhr = 0; int pim_nbrs = 0; + int pim_ifchannels = 0; json_object *json = NULL; json_object *json_row = NULL; json_object *json_tmp; @@ -1056,6 +1067,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj) continue; pim_nbrs = pim_ifp->pim_neighbor_list->count; + pim_ifchannels = pim_ifp->pim_ifchannel_list->count; fhr = 0; for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode, up)) @@ -1066,6 +1078,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj) json_row = json_object_new_object(); json_object_pim_ifp_add(json_row, ifp); json_object_int_add(json_row, "pimNeighbors", pim_nbrs); + json_object_int_add(json_row, "pimIfChannels", pim_ifchannels); json_object_int_add(json_row, "firstHopRouter", fhr); json_object_string_add(json_row, "pimDesignatedRouter", inet_ntoa(pim_ifp->pim_dr_addr)); @@ -1078,7 +1091,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj) if (uj) { vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE); } else { - vty_out(vty, "Interface State Address PIM Nbrs PIM DR FHR%s", VTY_NEWLINE); + vty_out(vty, "Interface State Address PIM Nbrs PIM DR FHR IfChannels%s", VTY_NEWLINE); json_object_object_foreach(json, key, val) { vty_out(vty, "%-9s ", key); @@ -1100,7 +1113,10 @@ static void pim_show_interfaces(struct vty *vty, u_char uj) } 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)); 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) - continue; - - pim_inet4_dump("", p->u.prefix4, - neigh_sec_str, sizeof(neigh_sec_str)); + prefix2str(p, neigh_sec_str, sizeof(neigh_sec_str)); vty_out(vty, "%-9s %-15s %-15s %-15s%s", ifp->name, @@ -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) { struct listnode *ifnode; @@ -2793,6 +2849,99 @@ DEFUN (show_ip_pim_rpf, 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_str, sizeof (grp_str)); + pim_addr_dump ("", &nexthop.mrib_nexthop_addr, + nexthop_addr_str, sizeof (nexthop_addr_str)); + vty_out (vty, "Group %s --- Nexthop %s Interface %s %s", grp_str, + nexthop_addr_str, nexthop.interface->name, VTY_NEWLINE); + + return CMD_SUCCESS; +} + static void show_multicast_interfaces(struct vty *vty) { struct listnode *node; @@ -2871,15 +3020,17 @@ DEFUN (show_ip_multicast, PIM_MAX_USABLE_VIFS, VTY_NEWLINE); - vty_out(vty, "%s", VTY_NEWLINE); - vty_out(vty, "Upstream Join Timer: %d secs%s", - qpim_t_periodic, - VTY_NEWLINE); - vty_out(vty, "Join/Prune Holdtime: %d secs%s", - PIM_JP_HOLDTIME, - VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, "Upstream Join Timer: %d secs%s", + qpim_t_periodic, VTY_NEWLINE); + vty_out (vty, "Join/Prune Holdtime: %d secs%s", + PIM_JP_HOLDTIME, VTY_NEWLINE); + vty_out (vty, "PIM ECMP: %s%s", + qpim_ecmp_enable ? "Enable" : "Disable", VTY_NEWLINE); + vty_out (vty, "PIM ECMP Rebalance: %s%s", + qpim_ecmp_rebalance_enable ? "Enable" : "Disable", VTY_NEWLINE); - vty_out(vty, "%s", VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); show_rpf_refresh_stats(vty, now, NULL); @@ -3410,6 +3561,35 @@ pim_rp_cmd_worker (struct vty *vty, const char *rp, const char *group, const cha return CMD_SUCCESS; } +DEFUN (ip_pim_spt_switchover_infinity, + ip_pim_spt_switchover_infinity_cmd, + "ip pim spt-switchover infinity-and-beyond", + IP_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n") +{ + pimg->spt_switchover = PIM_SPT_INFINITY; + + pim_upstream_remove_lhr_star_pimreg(); + return CMD_SUCCESS; +} + +DEFUN (no_ip_pim_spt_switchover_infinity, + no_ip_pim_spt_switchover_infinity_cmd, + "no ip pim spt-switchover infinity-and-beyond", + NO_STR + IP_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n") +{ + pimg->spt_switchover = PIM_SPT_IMMEDIATE; + + pim_upstream_add_lhr_star_pimreg(); + return CMD_SUCCESS; +} + DEFUN (ip_pim_joinprune_time, ip_pim_joinprune_time_cmd, "ip pim join-prune-interval <60-600>", @@ -3510,6 +3690,31 @@ DEFUN (no_ip_pim_packets, return CMD_SUCCESS; } +DEFUN (ip_pim_v6_secondary, + ip_pim_v6_secondary_cmd, + "ip pim send-v6-secondary", + IP_STR + "pim multicast routing\n" + "Send v6 secondary addresses\n") +{ + pimg->send_v6_secondary = 1; + + return CMD_SUCCESS; +} + +DEFUN (no_ip_pim_v6_secondary, + no_ip_pim_v6_secondary_cmd, + "no ip pim send-v6-secondary", + NO_STR + IP_STR + "pim multicast routing\n" + "Send v6 secondary addresses\n") +{ + pimg->send_v6_secondary = 0; + + return CMD_SUCCESS; +} + DEFUN (ip_pim_rp, ip_pim_rp_cmd, "ip pim rp A.B.C.D [A.B.C.D/M]", @@ -3577,10 +3782,10 @@ DEFUN (no_ip_pim_rp, "ip address of RP\n" "Group Address range to cover\n") { - int idx_ipv4 = 4; + int idx_ipv4 = 4, idx_group = 0; - if (argc == (idx_ipv4 + 1)) - return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, argv[idx_ipv4 + 1]->arg, NULL); + if (argv_find (argv, argc, "A.B.C.D/M", &idx_group)) + return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, argv[idx_group]->arg, NULL); else return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, NULL, NULL); } @@ -3826,6 +4031,58 @@ DEFUN (no_ip_ssmpingd, return CMD_SUCCESS; } +DEFUN (ip_pim_ecmp, + ip_pim_ecmp_cmd, + "ip pim ecmp", + IP_STR + "pim multicast routing\n" + "Enable PIM ECMP \n") +{ + qpim_ecmp_enable = 1; + + return CMD_SUCCESS; +} + +DEFUN (no_ip_pim_ecmp, + no_ip_pim_ecmp_cmd, + "no ip pim ecmp", + NO_STR + IP_STR + "pim multicast routing\n" + "Disable PIM ECMP \n") +{ + qpim_ecmp_enable = 0; + + return CMD_SUCCESS; +} + +DEFUN (ip_pim_ecmp_rebalance, + ip_pim_ecmp_rebalance_cmd, + "ip pim ecmp rebalance", + IP_STR + "pim multicast routing\n" + "Enable PIM ECMP \n" + "Enable PIM ECMP Rebalance\n") +{ + qpim_ecmp_rebalance_enable = 1; + + return CMD_SUCCESS; +} + +DEFUN (no_ip_pim_ecmp_rebalance, + no_ip_pim_ecmp_rebalance_cmd, + "no ip pim ecmp rebalance", + NO_STR + IP_STR + "pim multicast routing\n" + "Disable PIM ECMP \n" + "Disable PIM ECMP Rebalance\n") +{ + qpim_ecmp_rebalance_enable = 0; + + return CMD_SUCCESS; +} + static int pim_cmd_igmp_start (struct vty *vty, struct interface *ifp) { @@ -6149,13 +6406,16 @@ DEFUN (show_ip_msdp_sa_sg, "JavaScript Object Notation\n") { u_char uj = use_json(argc, argv); - if (uj) - argc--; - if (argc == 5) - ip_msdp_show_sa_sg(vty, argv[4]->arg, argv[5]->arg, uj); - else if (argc == 4) - ip_msdp_show_sa_addr(vty, argv[4]->arg, uj); + int idx = 0; + char *src_ip = argv_find (argv, argc, "A.B.C.D", &idx) ? argv[idx++]->arg : NULL; + char *grp_ip = idx < argc && argv_find (argv, argc, "A.B.C.D", &idx) ? + argv[idx]->arg : NULL; + + if (src_ip && grp_ip) + ip_msdp_show_sa_sg(vty, src_ip, grp_ip, uj); + else if (src_ip) + ip_msdp_show_sa_addr(vty, src_ip, uj); else ip_msdp_show_sa(vty, uj); @@ -6181,16 +6441,24 @@ void pim_cmd_init() install_element (CONFIG_NODE, &ip_pim_ssm_prefix_list_cmd); install_element (CONFIG_NODE, &ip_pim_register_suppress_cmd); install_element (CONFIG_NODE, &no_ip_pim_register_suppress_cmd); + install_element (CONFIG_NODE, &ip_pim_spt_switchover_infinity_cmd); + install_element (CONFIG_NODE, &no_ip_pim_spt_switchover_infinity_cmd); install_element (CONFIG_NODE, &ip_pim_joinprune_time_cmd); install_element (CONFIG_NODE, &no_ip_pim_joinprune_time_cmd); install_element (CONFIG_NODE, &ip_pim_keep_alive_cmd); install_element (CONFIG_NODE, &no_ip_pim_keep_alive_cmd); install_element (CONFIG_NODE, &ip_pim_packets_cmd); install_element (CONFIG_NODE, &no_ip_pim_packets_cmd); + install_element (CONFIG_NODE, &ip_pim_v6_secondary_cmd); + install_element (CONFIG_NODE, &no_ip_pim_v6_secondary_cmd); install_element (CONFIG_NODE, &ip_ssmpingd_cmd); install_element (CONFIG_NODE, &no_ip_ssmpingd_cmd); install_element (CONFIG_NODE, &ip_msdp_peer_cmd); install_element (CONFIG_NODE, &no_ip_msdp_peer_cmd); + install_element (CONFIG_NODE, &ip_pim_ecmp_cmd); + install_element (CONFIG_NODE, &no_ip_pim_ecmp_cmd); + install_element (CONFIG_NODE, &ip_pim_ecmp_rebalance_cmd); + install_element (CONFIG_NODE, &no_ip_pim_ecmp_rebalance_cmd); install_element (INTERFACE_NODE, &interface_ip_igmp_cmd); install_element (INTERFACE_NODE, &interface_no_ip_igmp_cmd); @@ -6246,6 +6514,8 @@ void pim_cmd_init() install_element (VIEW_NODE, &show_ip_rib_cmd); install_element (VIEW_NODE, &show_ip_ssmpingd_cmd); install_element (VIEW_NODE, &show_debugging_pim_cmd); + install_element (VIEW_NODE, &show_ip_pim_nexthop_cmd); + install_element (VIEW_NODE, &show_ip_pim_nexthop_lookup_cmd); install_element (ENABLE_NODE, &clear_ip_interfaces_cmd); install_element (ENABLE_NODE, &clear_ip_igmp_interfaces_cmd); diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c index 3d7ae4ad22..ee9433d797 100644 --- a/pimd/pim_hello.c +++ b/pimd/pim_hello.c @@ -428,15 +428,14 @@ int pim_hello_recv(struct interface *ifp, return 0; } -int pim_hello_build_tlv(const char *ifname, +int pim_hello_build_tlv(struct interface *ifp, uint8_t *tlv_buf, int tlv_buf_size, uint16_t holdtime, uint32_t dr_priority, uint32_t generation_id, uint16_t propagation_delay, uint16_t override_interval, - int can_disable_join_suppression, - struct list *ifconnected) + int can_disable_join_suppression) { uint8_t *curr = tlv_buf; uint8_t *pastend = tlv_buf + tlv_buf_size; @@ -454,7 +453,7 @@ int pim_hello_build_tlv(const char *ifname, if (!curr) { if (PIM_DEBUG_PIM_HELLO) { zlog_debug("%s: could not set PIM hello Holdtime option for interface %s", - __PRETTY_FUNCTION__, ifname); + __PRETTY_FUNCTION__, ifp->name); } return -1; } @@ -468,7 +467,7 @@ int pim_hello_build_tlv(const char *ifname, if (!tmp) { if (PIM_DEBUG_PIM_HELLO) { zlog_debug("%s: could not set PIM LAN Prune Delay option for interface %s", - __PRETTY_FUNCTION__, ifname); + __PRETTY_FUNCTION__, ifp->name); } return -1; } @@ -485,7 +484,7 @@ int pim_hello_build_tlv(const char *ifname, if (!curr) { if (PIM_DEBUG_PIM_HELLO) { zlog_debug("%s: could not set PIM hello DR Priority option for interface %s", - __PRETTY_FUNCTION__, ifname); + __PRETTY_FUNCTION__, ifp->name); } return -2; } @@ -498,23 +497,38 @@ int pim_hello_build_tlv(const char *ifname, if (!curr) { if (PIM_DEBUG_PIM_HELLO) { zlog_debug("%s: could not set PIM hello Generation ID option for interface %s", - __PRETTY_FUNCTION__, ifname); + __PRETTY_FUNCTION__, ifp->name); } return -3; } /* Secondary Address List */ - if (ifconnected) { + if (ifp->connected->count) { curr = pim_tlv_append_addrlist_ucast(curr, pastend, - ifconnected); + ifp->connected, + AF_INET); if (!curr) { if (PIM_DEBUG_PIM_HELLO) { - zlog_debug("%s: could not set PIM hello Secondary Address List option for interface %s", - __PRETTY_FUNCTION__, ifname); + zlog_debug("%s: could not set PIM hello v4 Secondary Address List option for interface %s", + __PRETTY_FUNCTION__, ifp->name); } return -4; } + if (pimg->send_v6_secondary) + { + curr = pim_tlv_append_addrlist_ucast(curr, + pastend, + ifp->connected, + AF_INET6); + if (!curr) { + if (PIM_DEBUG_PIM_HELLO) { + zlog_debug("%s: could not sent PIM hello v6 secondary Address List option for interface %s", + __PRETTY_FUNCTION__, ifp->name); + } + return -4; + } + } } return curr - tlv_buf; diff --git a/pimd/pim_hello.h b/pimd/pim_hello.h index 3a6d3361ba..1f8b348bd7 100644 --- a/pimd/pim_hello.h +++ b/pimd/pim_hello.h @@ -29,15 +29,14 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size); -int pim_hello_build_tlv(const char *ifname, +int pim_hello_build_tlv(struct interface *ifp, uint8_t *tlv_buf, int tlv_buf_size, uint16_t holdtime, uint32_t dr_priority, uint32_t generation_id, uint16_t propagation_delay, uint16_t override_interval, - int can_disable_join_suppression, - struct list *ifconnected); + int can_disable_join_suppression); void pim_hello_require(struct interface *ifp); diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 0864796431..524f2ee0b3 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -30,6 +30,7 @@ #include "hash.h" #include "pimd.h" +#include "pim_zebra.h" #include "pim_iface.h" #include "pim_igmp.h" #include "pim_mroute.h" @@ -42,6 +43,7 @@ #include "pim_time.h" #include "pim_ssmpingd.h" #include "pim_rp.h" +#include "pim_nht.h" struct interface *pim_regiface = NULL; struct list *pim_ifchannel_list = NULL; @@ -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 *sec2 = p2; - if (ntohl(sec1->addr.s_addr) < ntohl(sec2->addr.s_addr)) + if (sec1->addr.family == AF_INET && + sec2->addr.family == AF_INET6) return -1; - if (ntohl(sec1->addr.s_addr) > ntohl(sec2->addr.s_addr)) + if (sec1->addr.family == AF_INET6 && + sec2->addr.family == AF_INET) return 1; + if (sec1->addr.family == AF_INET) + { + if (ntohl(sec1->addr.u.prefix4.s_addr) < ntohl(sec2->addr.u.prefix4.s_addr)) + return -1; + + if (ntohl(sec1->addr.u.prefix4.s_addr) > ntohl(sec2->addr.u.prefix4.s_addr)) + return 1; + } + else + { + return memcmp (&sec1->addr.u.prefix6, + &sec2->addr.u.prefix6, + sizeof (struct in6_addr)); + } + return 0; } @@ -339,7 +358,7 @@ static void pim_sec_addr_free(struct pim_secondary_addr *sec_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 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)) { - if (sec_addr->addr.s_addr == addr.s_addr) { + if (prefix_cmp(&sec_addr->addr, 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); } -static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct in_addr addr) +static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct prefix *addr) { int changed = 0; struct pim_secondary_addr *sec_addr; @@ -391,7 +410,7 @@ static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct in_addr addr) } changed = 1; - sec_addr->addr = addr; + sec_addr->addr = *addr; listnode_add_sort(pim_ifp->sec_addr_list, sec_addr); return changed; @@ -433,10 +452,6 @@ static int pim_sec_addr_update(struct interface *ifp) for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { struct prefix *p = ifc->address; - if (p->family != AF_INET) { - continue; - } - if (PIM_INADDR_IS_ANY(p->u.prefix4)) { continue; } @@ -446,7 +461,7 @@ static int pim_sec_addr_update(struct interface *ifp) continue; } - if (pim_sec_addr_add(pim_ifp, p->u.prefix4)) { + if (pim_sec_addr_add(pim_ifp, p)) { changed = 1; } } @@ -571,33 +586,55 @@ void pim_if_addr_add(struct connected *ifc) detect_address_change(ifp, 0, __PRETTY_FUNCTION__); + if (ifc->address->family != AF_INET) + return; + if (PIM_IF_TEST_IGMP(pim_ifp->options)) { struct igmp_sock *igmp; /* lookup IGMP socket */ igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, - ifaddr); + ifaddr); if (!igmp) { /* if addr new, add IGMP socket */ pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp); } } /* igmp */ - if (PIM_IF_TEST_PIM(pim_ifp->options)) { + 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 ? */ - if (pim_ifp->pim_sock_fd < 0) { - if (pim_sock_add(ifp)) { - zlog_warn("Failure creating PIM socket for interface %s", - ifp->name); - } - } + /* Interface has a valid socket ? */ + if (pim_ifp->pim_sock_fd < 0) + { + if (pim_sock_add (ifp)) + { + zlog_warn ("Failure creating PIM socket for interface %s", + ifp->name); + } + } + struct pim_nexthop_cache *pnc = NULL; + struct pim_rpf rpf; + struct zclient *zclient = NULL; - } - } /* pim */ + zclient = pim_zebra_zclient_get (); + /* RP config might come prior to (local RP's interface) IF UP event. + In this case, pnc would not have pim enabled nexthops. + Once Interface is UP and pim info is available, reregister + with RNH address to receive update and add the interface as nexthop. */ + memset (&rpf, 0, sizeof (struct pim_rpf)); + rpf.rpf_addr.family = AF_INET; + rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN; + rpf.rpf_addr.u.prefix4 = ifc->address->u.prefix4; + pnc = pim_nexthop_cache_find (&rpf); + if (pnc) + pim_sendmsg_zebra_rnh (zclient, pnc, + ZEBRA_NEXTHOP_REGISTER); + } + } /* pim */ /* PIM or IGMP is enabled on interface, and there is at least one @@ -675,14 +712,17 @@ void pim_if_addr_del(struct connected *ifc, int force_prim_as_any) ifp = ifc->ifp; zassert(ifp); + if (ifc->address->family != AF_INET) + return; + if (PIM_DEBUG_ZEBRA) { char buf[BUFSIZ]; prefix2str(ifc->address, buf, BUFSIZ); zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s", - __PRETTY_FUNCTION__, - ifp->name, ifp->ifindex, buf, - CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ? - "secondary" : "primary"); + __PRETTY_FUNCTION__, + ifp->name, ifp->ifindex, buf, + CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ? + "secondary" : "primary"); } detect_address_change(ifp, force_prim_as_any, __PRETTY_FUNCTION__); @@ -709,12 +749,9 @@ void pim_if_addr_add_all(struct interface *ifp) struct prefix *p = ifc->address; if (p->family != AF_INET) - { - v6_addrs++; - continue; - } - - v4_addrs++; + v6_addrs++; + else + v4_addrs++; pim_if_addr_add(ifc); } @@ -1105,6 +1142,7 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, struct listnode *neighnode; struct pim_neighbor *neigh; struct pim_interface *pim_ifp; + struct prefix p; zassert(ifp); @@ -1116,6 +1154,10 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, return 0; } + p.family = AF_INET; + p.u.prefix4 = addr; + p.prefixlen = IPV4_MAX_PREFIXLEN; + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) { /* primary address ? */ @@ -1123,7 +1165,7 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, return neigh; /* secondary address ? */ - if (pim_neighbor_find_secondary(neigh, addr)) + if (pim_neighbor_find_secondary(neigh, &p)) return neigh; } diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index e98c17fed2..c42c691067 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -64,7 +64,7 @@ enum pim_secondary_addr_flags { }; struct pim_secondary_addr { - struct in_addr addr; + struct prefix addr; enum pim_secondary_addr_flags flags; }; diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index e6b4ba92a9..ebd36f8782 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -1006,6 +1006,8 @@ pim_ifchannel_local_membership_add(struct interface *ifp, 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; diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 2fb243b9bd..ce2f98f318 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -178,6 +178,15 @@ pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg up->channel_oil->cc.pktcnt++; PIM_UPSTREAM_FLAG_SET_FHR(up->flags); + // resolve mfcc_parent prior to mroute_add in channel_add_oif + if (up->channel_oil->oil.mfcc_parent >= MAXVIFS) + { + int vif_index = 0; + vif_index = + pim_if_find_vifindex_by_ifindex (up->rpf.source_nexthop. + interface->ifindex); + up->channel_oil->oil.mfcc_parent = vif_index; + } pim_register_join (up); return 0; @@ -200,6 +209,30 @@ pim_mroute_msg_wholepkt (int fd, struct interface *ifp, const char *buf) up = pim_upstream_find(&sg); if (!up) { + struct prefix_sg star = sg; + star.src.s_addr = INADDR_ANY; + + up = pim_upstream_find(&star); + + if (up && PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags)) + { + up = pim_upstream_add (&sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_LHR, __PRETTY_FUNCTION__); + if (!up) + { + if (PIM_DEBUG_MROUTE) + zlog_debug ("%s: Unable to create upstream information for %s", + __PRETTY_FUNCTION__, pim_str_sg_dump (&sg)); + return 0; + } + pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time); + pim_upstream_inherited_olist (up); + pim_upstream_switch(up, PIM_UPSTREAM_JOINED); + + if (PIM_DEBUG_MROUTE) + zlog_debug ("%s: Creating %s upstream on LHR", + __PRETTY_FUNCTION__, up->sg_str); + return 0; + } if (PIM_DEBUG_MROUTE_DETAIL) { zlog_debug("%s: Unable to find upstream channel WHOLEPKT%s", __PRETTY_FUNCTION__, pim_str_sg_dump (&sg)); @@ -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))); } - /*reset incoming vifi and kernel installed flags*/ + //Reset kernel installed flag c_oil->installed = 0; - c_oil->oil.mfcc_parent = MAXVIFS; return 0; } diff --git a/pimd/pim_msg.h b/pimd/pim_msg.h index de663aa3b5..e5676289b7 100644 --- a/pimd/pim_msg.h +++ b/pimd/pim_msg.h @@ -34,7 +34,11 @@ From: http://www.iana.org/assignments/address-family-numbers */ -#define PIM_MSG_ADDRESS_FAMILY_IPV4 (1) +enum pim_msg_address_family { + PIM_MSG_ADDRESS_FAMILY_RESERVED, + PIM_MSG_ADDRESS_FAMILY_IPV4, + PIM_MSG_ADDRESS_FAMILY_IPV6, +}; /* * Network Order pim_msg_hdr diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index c1325df260..c04a625485 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -423,6 +423,31 @@ void pim_neighbor_free(struct 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 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); + if (PIM_DEBUG_PIM_TRACE_DETAIL) + { + char str[INET_ADDRSTRLEN]; + pim_inet4_dump("", source_addr, str, sizeof (str)); + zlog_debug ("%s: neighbor %s added ", __PRETTY_FUNCTION__, str); + } /* 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(); + /* RNH can send nexthop update prior to PIM neibhor UP + in that case nexthop cache would not consider this neighbor + as RPF. + Upon PIM neighbor UP, iterate all RPs and update + nexthop cache with this neighbor. + */ + pim_resolve_rp_nh (); + pim_rp_setup (); pim_neighbor_rpf_update(); @@ -669,7 +708,7 @@ void pim_neighbor_delete_all(struct interface *ifp, } struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh, - struct in_addr addr) + struct prefix *addr) { struct listnode *node; struct prefix *p; @@ -678,14 +717,11 @@ struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh, return 0; for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) { - if (p->family == AF_INET) { - if (addr.s_addr == p->u.prefix4.s_addr) { - return p; - } - } + if (prefix_same (p, addr)) + return p; } - return 0; + return NULL; } /* @@ -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, neigh)) { { - struct prefix *p = pim_neighbor_find_secondary(neigh, addr->u.prefix4); + struct prefix *p = pim_neighbor_find_secondary(neigh, addr); if (p) { char addr_str[INET_ADDRSTRLEN]; char this_neigh_str[INET_ADDRSTRLEN]; diff --git a/pimd/pim_neighbor.h b/pimd/pim_neighbor.h index 986721666e..e27920fdd8 100644 --- a/pimd/pim_neighbor.h +++ b/pimd/pim_neighbor.h @@ -50,7 +50,8 @@ void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime); void pim_neighbor_free(struct pim_neighbor *neigh); struct pim_neighbor *pim_neighbor_find(struct interface *ifp, struct in_addr source_addr); - +struct pim_neighbor *pim_neighbor_find_by_secondary (struct interface *ifp, + struct prefix *src); 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, struct list *addr_list); struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh, - struct in_addr addr); + struct prefix *addr); int pim_if_dr_election(struct interface *ifp); #endif /* PIM_NEIGHBOR_H */ diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index fe96d01a06..23efd554ea 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -39,12 +39,13 @@ #include "pim_join.h" #include "pim_jp_agg.h" #include "pim_zebra.h" +#include "pim_zlookup.h" /** * pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister * command to Zebra. */ -static void +void pim_sendmsg_zebra_rnh (struct zclient *zclient, struct pim_nexthop_cache *pnc, int command) { @@ -87,9 +88,9 @@ pim_sendmsg_zebra_rnh (struct zclient *zclient, struct pim_nexthop_cache *pnc, { char buf[PREFIX2STR_BUFFER]; prefix2str (p, buf, sizeof (buf)); - zlog_debug ("%s: NHT Addr %s %sregistered with Zebra ret:%d ", - __PRETTY_FUNCTION__, buf, - (command == ZEBRA_NEXTHOP_REGISTER) ? " " : "de", ret); + zlog_debug ("%s: NHT %sregistered addr %s with Zebra ret:%d ", + __PRETTY_FUNCTION__, + (command == ZEBRA_NEXTHOP_REGISTER) ? " " : "de", buf, ret); } return; @@ -149,7 +150,8 @@ pim_nexthop_cache_add (struct pim_rpf *rpf_addr) /* This API is used to Register an address with Zebra */ int pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up, - struct rp_info *rp) + struct rp_info *rp, + struct pim_nexthop_cache *out_pnc) { struct pim_nexthop_cache *pnc = NULL; struct pim_rpf rpf; @@ -174,11 +176,14 @@ pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up, } pnc = pim_nexthop_cache_add (&rpf); if (pnc) - pim_sendmsg_zebra_rnh (zclient, pnc, - ZEBRA_NEXTHOP_REGISTER); + pim_sendmsg_zebra_rnh (zclient, pnc, ZEBRA_NEXTHOP_REGISTER); else { - zlog_warn ("%s: pnc node allocation failed. ", __PRETTY_FUNCTION__); + char rpf_str[PREFIX_STRLEN]; + pim_addr_dump ("", 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]; pim_addr_dump ("", &rp->rp.rpf_addr, rp_str, sizeof (rp_str)); - zlog_debug ("%s: NHT add RP %s node to cached list", + zlog_debug ("%s: Add RP %s node to pnc cached list", __PRETTY_FUNCTION__, rp_str); } listnode_add_sort (pnc->rp_list, rp); @@ -209,15 +214,18 @@ pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up, char buf[PREFIX2STR_BUFFER]; prefix2str (addr, buf, sizeof (buf)); zlog_debug - ("%s: NHT add upstream %s node to cached list, rpf %s", + ("%s: Add upstream %s node to pnc cached list, rpf %s", __PRETTY_FUNCTION__, up->sg_str, buf); } listnode_add_sort (pnc->upstream_list, up); } } - if (CHECK_FLAG (pnc->flags, PIM_NEXTHOP_VALID)) - return 1; + if (pnc && CHECK_FLAG (pnc->flags, PIM_NEXTHOP_VALID)) + { + memcpy (out_pnc, pnc, sizeof (struct pim_nexthop_cache)); + return 1; + } return 0; } @@ -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) { - pim_sendmsg_zebra_rnh (zclient, pnc, - ZEBRA_NEXTHOP_UNREGISTER); + pim_sendmsg_zebra_rnh (zclient, pnc, ZEBRA_NEXTHOP_UNREGISTER); list_delete (pnc->rp_list); list_delete (pnc->upstream_list); @@ -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) continue; - if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, - rp_info->rp.rpf_addr.u.prefix4, 1) != 0) - { - if (PIM_DEBUG_PIM_TRACE) - zlog_debug ("Unable to lookup nexthop for rp specified"); - ret++; - continue; - } + //Compute PIM RPF using cached nexthop + pim_ecmp_nexthop_search (pnc, &rp_info->rp.source_nexthop, + &rp_info->rp.rpf_addr, &rp_info->group, 1); if (PIM_DEBUG_TRACE) { char rp_str[PREFIX_STRLEN]; pim_addr_dump ("", &rp_info->rp.rpf_addr, rp_str, sizeof (rp_str)); - zlog_debug ("%s: NHT update nexthop for RP %s to interface %s ", + zlog_debug ("%s: NHT update, nexthop for RP %s is interface %s ", __PRETTY_FUNCTION__, rp_str, rp_info->rp.source_nexthop.interface->name); } @@ -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 ("", nbr->source_addr, str1, + sizeof (str1)); + pim_addr_dump ("", nht_p, str, sizeof (str)); + zlog_debug + ("%s: addr %s new nexthop addr %s ifindex %d ", + __PRETTY_FUNCTION__, str, str1, nh_node->ifindex); + } + } + } + } + } +} + /* Update Upstream nexthop info based on Nexthop update received from Zebra.*/ static int pim_update_upstream_nh (struct pim_nexthop_cache *pnc) @@ -312,8 +356,8 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc) struct listnode *ifnode; struct listnode *up_nextnode; struct listnode *node; - struct pim_upstream *up; - struct interface *ifp; + struct pim_upstream *up = NULL; + struct interface *ifp = NULL; int vif_index = 0; for (ALL_LIST_ELEMENTS (pnc->upstream_list, up_node, up_nextnode, up)) @@ -326,6 +370,26 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc) if (rpf_result == PIM_RPF_FAILURE) continue; + /* update kernel multicast forwarding cache (MFC) */ + if (up->channel_oil) + { + vif_index = + pim_if_find_vifindex_by_ifindex (up->rpf. + source_nexthop.interface-> + ifindex); + /* Pass Current selected NH vif index to mroute download */ + if (vif_index) + pim_scan_individual_oil (up->channel_oil, vif_index); + else + { + if (PIM_DEBUG_ZEBRA) + zlog_debug + ("%s: NHT upstream %s channel_oil IIF %s vif_index is not valid", + __PRETTY_FUNCTION__, up->sg_str, + up->rpf.source_nexthop.interface->name); + } + } + if (rpf_result == PIM_RPF_CHANGED) { struct pim_neighbor *nbr; @@ -377,7 +441,7 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc) returning PIM_RPF_CHANGED ? */ pim_upstream_update_join_desired (up); - } /* PIM_RPF_CHANGED */ + } /* PIM_RPF_CHANGED */ if (PIM_DEBUG_TRACE) { @@ -386,26 +450,7 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc) old.source_nexthop.interface->name, up->rpf.source_nexthop.interface->name); } - /* update kernel multicast forwarding cache (MFC) */ - if (up->channel_oil) - { - vif_index = - pim_if_find_vifindex_by_ifindex (up->rpf. - source_nexthop.interface-> - ifindex); - /* Pass Current selected NH vif index to mroute download */ - if (vif_index) - pim_scan_individual_oil (up->channel_oil, vif_index); - else - { - if (PIM_DEBUG_ZEBRA) - zlog_debug ("%s: NHT upstream %s channel_oil IIF %s vif_index is not valid", - __PRETTY_FUNCTION__, up->sg_str, - up->rpf.source_nexthop.interface->name); - } - } - - } /* for (pnc->upstream_list) */ + } /* for (pnc->upstream_list) */ for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp)) if (ifp->info) @@ -426,10 +471,209 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc) return 0; } -/* - * This API is used to parse Registered address nexthop update - * coming from Zebra - */ +uint32_t +pim_compute_ecmp_hash (struct prefix * src, struct prefix * grp) +{ + uint32_t hash_val; + uint32_t s = 0, g = 0; + + if ((!src)) + return 0; + + switch (src->family) + { + case AF_INET: + { + s = src->u.prefix4.s_addr; + s = s == 0 ? 1 : s; + if (grp) + g = grp->u.prefix4.s_addr; + } + break; + default: + break; + } + + hash_val = jhash_2words (g, s, 101); + if (PIM_DEBUG_TRACE) + { + char buf[PREFIX2STR_BUFFER]; + char bufg[PREFIX2STR_BUFFER]; + prefix2str (src, buf, sizeof (buf)); + if (grp) + prefix2str (grp, bufg, sizeof (bufg)); + zlog_debug ("%s: addr %s %s hash_val %u", __PRETTY_FUNCTION__, buf, + grp ? bufg : "", hash_val); + + } + return hash_val; +} + +int +pim_ecmp_nexthop_search (struct pim_nexthop_cache *pnc, + struct pim_nexthop *nexthop, struct prefix *src, + struct prefix *grp, int neighbor_needed) +{ + struct pim_neighbor *nbr = NULL; + struct nexthop *nh_node = NULL; + ifindex_t first_ifindex; + struct interface *ifp = NULL; + uint32_t hash_val = 0, mod_val = 0; + uint8_t nh_iter = 0, found = 0; + + if (!pnc || !pnc->nexthop_num || !nexthop) + return -1; + + if (qpim_ecmp_enable) + { + //User configured knob to explicitly switch to new path. + if (qpim_ecmp_rebalance_enable == 0) + { + //Current Nexthop is VALID then stay on the current path. + if (nexthop->interface && nexthop->interface->info && + nexthop->mrib_nexthop_addr.u.prefix4.s_addr != + PIM_NET_INADDR_ANY) + { + if (neighbor_needed + && !pim_if_connected_to_source (nexthop->interface, + src->u.prefix4)) + { + nbr = pim_neighbor_find (nexthop->interface, + nexthop->mrib_nexthop_addr. + u.prefix4); + if (!nbr && !if_is_loopback (nexthop->interface)) + { + if (PIM_DEBUG_TRACE) + zlog_debug ("%s: current nexthop does not have nbr ", + __PRETTY_FUNCTION__); + } + else + { + if (PIM_DEBUG_TRACE) + { + char src_str[INET_ADDRSTRLEN]; + pim_inet4_dump ("", src->u.prefix4, src_str, + sizeof (src_str)); + char grp_str[INET_ADDRSTRLEN]; + pim_inet4_dump ("", 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 ("", 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 ("", 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->u.prefix4, buf2, sizeof (buf2)); + if (grp) + pim_inet4_dump ("", grp->u.prefix4, buf3, + sizeof (buf3)); + pim_inet4_dump ("", + nexthop->mrib_nexthop_addr.u.prefix4, buf4, + sizeof (buf4)); + snprintf (buf, sizeof (buf), "%s if %u", + inet_ntoa (nh_node->gate.ipv4), nh_node->ifindex); + zlog_debug + ("%s: NHT %s %s selected nhop interface %s nhop %s (%s) mod_val:%u iter:%d ecmp_enable:%d", + __PRETTY_FUNCTION__, buf2, grp ? buf3 : " ", ifp->name, + buf, buf4, mod_val, nh_iter, qpim_ecmp_enable); + } + } + nh_iter++; + + } + + return 0; +} + +/* This API is used to parse Registered address nexthop update coming from Zebra */ int pim_parse_nexthop_update (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) @@ -437,7 +681,6 @@ pim_parse_nexthop_update (int command, struct zclient *zclient, struct stream *s; struct prefix p; struct nexthop *nexthop; - struct nexthop *oldnh; struct nexthop *nhlist_head = NULL; struct nexthop *nhlist_tail = NULL; uint32_t metric, distance; @@ -476,8 +719,9 @@ pim_parse_nexthop_update (int command, struct zclient *zclient, { char buf[PREFIX2STR_BUFFER]; prefix2str (&rpf.rpf_addr, buf, sizeof (buf)); - zlog_debug ("%s: NHT addr %s is not in local cached DB.", - __PRETTY_FUNCTION__, buf); + zlog_debug + ("%s: Skipping NHT update, addr %s is not in local cached DB.", + __PRETTY_FUNCTION__, buf); } return 0; } @@ -490,7 +734,7 @@ pim_parse_nexthop_update (int command, struct zclient *zclient, return 0; } - pnc->last_update = pim_time_monotonic_sec (); + pnc->last_update = pim_time_monotonic_usec (); distance = stream_getc (s); metric = stream_getl (s); nexthop_num = stream_getc (s); @@ -499,17 +743,15 @@ pim_parse_nexthop_update (int command, struct zclient *zclient, { char buf[PREFIX2STR_BUFFER]; prefix2str (&p, buf, sizeof (buf)); - zlog_debug ("%s: NHT Update for %s nexthop_num %d vrf:%d upcount %d rpcount %d", - __PRETTY_FUNCTION__, buf, nexthop_num, vrf_id, - listcount (pnc->upstream_list), listcount (pnc->rp_list)); + zlog_debug + ("%s: NHT Update for %s nexthop_num %d vrf:%d upcount %d rpcount %d", + __PRETTY_FUNCTION__, buf, nexthop_num, vrf_id, + listcount (pnc->upstream_list), listcount (pnc->rp_list)); } if (nexthop_num) { - pnc->flags |= PIM_NEXTHOP_VALID; - pnc->distance = distance; - pnc->metric = metric; - pnc->nexthop_num = nexthop_num; + pnc->nexthop_num = 0; //Only increment for pim enabled rpf. for (i = 0; i < nexthop_num; i++) { @@ -539,7 +781,34 @@ pim_parse_nexthop_update (int command, struct zclient *zclient, (nexthop->ifindex, VRF_DEFAULT)); /* Overwrite with Nbr address as NH addr */ if (nbr) - nexthop->gate.ipv4 = nbr->source_addr; + { + nexthop->gate.ipv4 = nbr->source_addr; + if (PIM_DEBUG_TRACE) + { + char str[INET_ADDRSTRLEN]; + pim_inet4_dump ("", nbr->source_addr, str, + sizeof (str)); + zlog_debug + ("%s: NHT using pim nbr addr %s ifindex %d as rpf", + __PRETTY_FUNCTION__, str, nexthop->ifindex); + } + } + else + { + if (PIM_DEBUG_TRACE) + { + struct interface *ifp1 = + if_lookup_by_index (nexthop->ifindex, + VRF_DEFAULT); + struct pim_interface *pim_ifp = ifp1->info; + zlog_debug + ("%s: NHT pim nbr not found on interface %s nbr count:%d ", + __PRETTY_FUNCTION__, ifp1->name, + pim_ifp->pim_neighbor_list->count); + } + //Mark nexthop address to 0 until PIM Nbr is resolved. + nexthop->gate.ipv4.s_addr = PIM_NET_INADDR_ANY; + } break; default: @@ -562,9 +831,10 @@ pim_parse_nexthop_update (int command, struct zclient *zclient, if (PIM_DEBUG_ZEBRA) { char buf[NEXTHOP_STRLEN]; - zlog_debug("%s: could not find interface for ifindex %d (addr %s)", - __PRETTY_FUNCTION__, - nexthop->ifindex, nexthop2str (nexthop, buf, sizeof (buf))); + zlog_debug + ("%s: could not find interface for ifindex %d (addr %s)", + __PRETTY_FUNCTION__, nexthop->ifindex, + nexthop2str (nexthop, buf, sizeof (buf))); } nexthop_free (nexthop); continue; @@ -594,14 +864,18 @@ pim_parse_nexthop_update (int command, struct zclient *zclient, nhlist_tail = nexthop; nhlist_head = nexthop; } - - for (oldnh = pnc->nexthop; oldnh; oldnh = oldnh->next) - if (nexthop_same_no_recurse (oldnh, nexthop)) - break; + //Only keep track of nexthops which are PIM enabled. + pnc->nexthop_num++; } /* Reset existing pnc->nexthop before assigning new list */ nexthops_free (pnc->nexthop); pnc->nexthop = nhlist_head; + if (pnc->nexthop_num) + { + pnc->flags |= PIM_NEXTHOP_VALID; + pnc->distance = distance; + pnc->metric = metric; + } } else { @@ -611,6 +885,16 @@ pim_parse_nexthop_update (int command, struct zclient *zclient, pnc->nexthop = NULL; } + if (PIM_DEBUG_TRACE) + { + char buf[PREFIX2STR_BUFFER]; + prefix2str (&p, buf, sizeof (buf)); + zlog_debug + ("%s: NHT Update for %s nexthop_num:%d pim nexthop_num %d vrf:%d up %d rp %d", + __PRETTY_FUNCTION__, buf, nexthop_num, pnc->nexthop_num, vrf_id, + listcount (pnc->upstream_list), listcount (pnc->rp_list)); + } + pim_rpf_set_refresh_time (); if (listcount (pnc->rp_list)) @@ -620,3 +904,142 @@ pim_parse_nexthop_update (int command, struct zclient *zclient, 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_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_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_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_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_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_tab[i].nexthop_addr, + nexthop_str, sizeof (nexthop_str)); + pim_inet4_dump ("", 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; +} diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h index 5348ec3704..b4b2d91e47 100644 --- a/pimd/pim_nht.h +++ b/pimd/pim_nht.h @@ -51,10 +51,19 @@ struct pim_nexthop_cache int pim_parse_nexthop_update (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id); int pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up, - struct rp_info *rp); + struct rp_info *rp, struct pim_nexthop_cache *out_pnc); void pim_delete_tracked_nexthop (struct prefix *addr, struct pim_upstream *up, struct rp_info *rp); struct pim_nexthop_cache *pim_nexthop_cache_add (struct pim_rpf *rpf_addr); struct pim_nexthop_cache *pim_nexthop_cache_find (struct pim_rpf *rpf); - +uint32_t pim_compute_ecmp_hash (struct prefix *src, struct prefix *grp); +int pim_ecmp_nexthop_search (struct pim_nexthop_cache * pnc, + struct pim_nexthop *nexthop, struct prefix *src, + struct prefix *grp, int neighbor_needed); +int pim_ecmp_nexthop_lookup (struct pim_nexthop *nexthop, struct in_addr addr, + struct prefix *src, struct prefix *grp, + int neighbor_needed); +void pim_sendmsg_zebra_rnh (struct zclient *zclient, struct pim_nexthop_cache *pnc, + int command); +void pim_resolve_upstream_nh (struct prefix *nht_p); #endif diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index 2701079053..2d4aa3febc 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -289,10 +289,10 @@ pim_channel_del_oif (struct channel_oil *channel_oil, char source_str[INET_ADDRSTRLEN]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); - zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d", + zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u IIF:%d OIF=%s vif_index=%d", __FILE__, __PRETTY_FUNCTION__, source_str, group_str, - proto_mask, oif->name, pim_ifp->mroute_vif_index); + proto_mask, channel_oil->oil.mfcc_parent ,oif->name, pim_ifp->mroute_vif_index); } return 0; diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index b2f858b7d9..9886cd6ad2 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -627,7 +627,7 @@ static int hello_send(struct interface *ifp, listcount(ifp->connected)); } - pim_tlv_size = pim_hello_build_tlv(ifp->name, + pim_tlv_size = pim_hello_build_tlv(ifp, pim_msg + PIM_PIM_MIN_LEN, sizeof(pim_msg) - PIM_PIM_MIN_LEN, holdtime, @@ -635,8 +635,7 @@ static int hello_send(struct interface *ifp, pim_ifp->pim_generation_id, pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec, - PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options), - ifp->connected); + PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options)); if (pim_tlv_size < 0) { return -1; } diff --git a/pimd/pim_register.c b/pimd/pim_register.c index 65a3e8714f..12f8dd53f2 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -187,6 +187,15 @@ pim_register_send (const uint8_t *buf, int buf_size, struct in_addr src, struct return; } + if (PIM_DEBUG_PIM_REG) + { + char rp_str[INET_ADDRSTRLEN]; + strcpy (rp_str, inet_ntoa (rpg->rpf_addr.u.prefix4)); + zlog_debug ("%s: Sending %s %sRegister Packet to %s on %s", + __PRETTY_FUNCTION__, up->sg_str, + null_register ? "NULL " : "", rp_str, ifp->name); + } + memset(buffer, 0, 10000); b1 = buffer + PIM_MSG_HEADER_LEN; *b1 |= null_register << 6; diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 78bbd14405..1dd5dae303 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -30,6 +30,7 @@ #include "vty.h" #include "vrf.h" #include "plist.h" +#include "nexthop.h" #include "pimd.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)) { - 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; } } @@ -280,7 +281,7 @@ pim_rp_check_interfaces (struct rp_info *rp_info) int pim_rp_new (const char *rp, const char *group_range, const char *plist) { - int result; + int result, ret = 0; struct rp_info *rp_info; struct rp_info *rp_all; struct prefix group_all; @@ -288,6 +289,7 @@ pim_rp_new (const char *rp, const char *group_range, const char *plist) struct rp_info *tmp_rp_info; char buffer[BUFSIZ]; struct prefix nht_p; + struct pim_nexthop_cache pnc; rp_info = XCALLOC (MTYPE_PIM_RP, sizeof (*rp_info)); if (!rp_info) @@ -387,21 +389,31 @@ pim_rp_new (const char *rp, const char *group_range, const char *plist) /* Register addr with Zebra NHT */ nht_p.family = AF_INET; nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = rp_all->rp.rpf_addr.u.prefix4; + nht_p.u.prefix4 = rp_all->rp.rpf_addr.u.prefix4; //RP address if (PIM_DEBUG_PIM_TRACE) { char buf[PREFIX2STR_BUFFER]; + char buf1[PREFIX2STR_BUFFER]; prefix2str (&nht_p, buf, sizeof (buf)); - zlog_debug ("%s: NHT Register rp_all addr %s with NHT ", - __PRETTY_FUNCTION__, buf); + prefix2str (&rp_all->group, buf1, sizeof (buf1)); + zlog_debug ("%s: NHT Register rp_all addr %s grp %s ", + __PRETTY_FUNCTION__, buf, buf1); + } + memset (&pnc, 0, sizeof (struct pim_nexthop_cache)); + if ((ret = + pim_find_or_track_nexthop (&nht_p, NULL, rp_all, &pnc)) == 1) + { + //Compute PIM RPF using Cached nexthop + pim_ecmp_nexthop_search (&pnc, &rp_all->rp.source_nexthop, + &nht_p, &rp_all->group, 1); + } + else + { + if (pim_nexthop_lookup (&rp_all->rp.source_nexthop, rp_all->rp.rpf_addr.u.prefix4, 1) != 0) + return PIM_RP_NO_PATH; } - pim_find_or_track_nexthop (&nht_p, NULL, rp_all); - - if (pim_nexthop_lookup (&rp_all->rp.source_nexthop, rp_all->rp.rpf_addr.u.prefix4, 1) != 0) - return PIM_RP_NO_PATH; - pim_rp_check_interfaces (rp_all); - pim_rp_refresh_group_to_rp_mapping(); + pim_rp_refresh_group_to_rp_mapping (); return PIM_SUCCESS; } @@ -451,13 +463,25 @@ pim_rp_new (const char *rp, const char *group_range, const char *plist) if (PIM_DEBUG_PIM_TRACE) { char buf[PREFIX2STR_BUFFER]; + char buf1[PREFIX2STR_BUFFER]; prefix2str (&nht_p, buf, sizeof (buf)); - zlog_debug ("%s: NHT Register RP addr %s with Zebra ", __PRETTY_FUNCTION__, buf); + prefix2str (&rp_info->group, buf1, sizeof (buf1)); + zlog_debug ("%s: NHT Register RP addr %s grp %s with Zebra ", + __PRETTY_FUNCTION__, buf, buf1); } - pim_find_or_track_nexthop (&nht_p, NULL, rp_info); - if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1) != 0) - return PIM_RP_NO_PATH; + memset (&pnc, 0, sizeof (struct pim_nexthop_cache)); + if ((ret = pim_find_or_track_nexthop (&nht_p, NULL, rp_info, &pnc)) == 1) + { + //Compute PIM RPF using Cached nexthop + pim_ecmp_nexthop_search (&pnc, &rp_info->rp.source_nexthop, + &nht_p, &rp_info->group, 1); + } + else + { + if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1) != 0) + return PIM_RP_NO_PATH; + } pim_rp_check_interfaces (rp_info); pim_rp_refresh_group_to_rp_mapping (); @@ -509,7 +533,8 @@ pim_rp_del (const char *rp, const char *group_range, const char *plist) { char buf[PREFIX2STR_BUFFER]; prefix2str (&nht_p, buf, sizeof (buf)); - zlog_debug ("%s: Deregister RP addr %s with NHT ", __PRETTY_FUNCTION__, buf); + zlog_debug ("%s: Deregister RP addr %s with Zebra ", __PRETTY_FUNCTION__, + buf); } pim_delete_tracked_nexthop (&nht_p, NULL, rp_info); @@ -535,17 +560,39 @@ pim_rp_setup (void) struct listnode *node; struct rp_info *rp_info; int ret = 0; + struct prefix nht_p; + struct pim_nexthop_cache pnc; for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info)) { if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE) continue; - if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1) != 0) + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; + memset (&pnc, 0, sizeof (struct pim_nexthop_cache)); + if ((pim_find_or_track_nexthop (&nht_p, NULL, rp_info, &pnc)) == 1) { - if (PIM_DEBUG_PIM_TRACE) - zlog_debug ("Unable to lookup nexthop for rp specified"); - ret++; + //Compute PIM RPF using Cached nexthop + pim_ecmp_nexthop_search (&pnc, &rp_info->rp.source_nexthop, + &nht_p, &rp_info->group, 1); + } + else + { + if (PIM_DEBUG_ZEBRA) + { + char buf[PREFIX2STR_BUFFER]; + prefix2str (&nht_p, buf, sizeof (buf)); + zlog_debug ("%s: NHT Local Nexthop not found for RP %s ", + __PRETTY_FUNCTION__, buf); + } + if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1) != 0) + { + if (PIM_DEBUG_PIM_TRACE) + zlog_debug ("Unable to lookup nexthop for rp specified"); + ret++; + } } } @@ -680,7 +727,43 @@ pim_rp_g (struct in_addr group) 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); } @@ -862,3 +945,54 @@ pim_rp_show_information (struct vty *vty, u_char uj) 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 ("", nbr->source_addr, + str1, sizeof (str1)); + pim_addr_dump ("", &nht_p, str, + sizeof (str)); + zlog_debug + ("%s: addr %s new nexthop addr %s ifindex %d ", + __PRETTY_FUNCTION__, str, str1, + nh_node->ifindex); + } + } + } + } + } + } +} diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h index 84ab9be482..df18c998d6 100644 --- a/pimd/pim_rp.h +++ b/pimd/pim_rp.h @@ -61,6 +61,6 @@ struct pim_rpf *pim_rp_g (struct in_addr group); #define RP(G) pim_rp_g ((G)) void pim_rp_show_information (struct vty *vty, u_char uj); - +void pim_resolve_rp_nh (void); int pim_rp_list_cmp (void *v1, void *v2); #endif diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index 400048738a..0f5fab0d93 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -67,11 +67,14 @@ int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, int nei { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("", 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->mrib_nexthop_addr, + nexthop_str, sizeof(nexthop_str)); + zlog_debug ("%s: Using last lookup for %s at %lld, %lld addr%s", __PRETTY_FUNCTION__, addr_str, nexthop->last_lookup_time, - last_route_change_time); + last_route_change_time, nexthop_str); } nexthop_lookups_avoided++; return 0; @@ -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 saved; struct prefix nht_p; + struct pim_nexthop_cache pnc; + int ret = 0; + struct prefix src, grp; saved.source_nexthop = rpf->source_nexthop; saved.rpf_addr = rpf->rpf_addr; - if (is_new) + if (is_new && PIM_DEBUG_ZEBRA) { - if (PIM_DEBUG_ZEBRA) - { - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", up->upstream_addr, source_str, sizeof(source_str)); - zlog_debug ("%s: NHT Register upstream %s addr %s with Zebra.", - __PRETTY_FUNCTION__, up->sg_str, source_str); - } - /* Register addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; - pim_find_or_track_nexthop (&nht_p, up, NULL); + char source_str[INET_ADDRSTRLEN]; + pim_inet4_dump ("", up->upstream_addr, source_str, + sizeof (source_str)); + zlog_debug ("%s: NHT Register upstream %s addr %s with Zebra.", + __PRETTY_FUNCTION__, up->sg_str, source_str); } + /* Register addr with Zebra NHT */ + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; - if (pim_nexthop_lookup(&rpf->source_nexthop, - up->upstream_addr, - !PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) && - !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags))) { - return PIM_RPF_FAILURE; - } + src.family = AF_INET; + src.prefixlen = IPV4_MAX_BITLEN; + src.u.prefix4 = up->upstream_addr; //RP or Src address + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = up->sg.grp; + memset (&pnc, 0, sizeof (struct pim_nexthop_cache)); + if ((ret = pim_find_or_track_nexthop (&nht_p, up, NULL, &pnc)) == 1) + { + if (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.u.prefix4 = pim_rpf_find_rpf_addr(up); diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index 5223f60e1b..259ed44c71 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -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_ipv6_encoding_len (2 + sizeof(struct in6_addr)) /* * 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)); return ucast_ipv4_encoding_len; break; + case AF_INET6: + *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV6; + ++buf; + *(uint8_t *)buf = 0; + ++buf; + memcpy (buf, &p->u.prefix6, sizeof (struct in6_addr)); + return ucast_ipv6_encoding_len; + break; default: return 0; break; @@ -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, const uint8_t *buf_pastend, - struct list *ifconnected) + struct list *ifconnected, + int family) { struct listnode *node; uint16_t option_len = 0; - uint8_t *curr; + size_t uel; node = listhead(ifconnected); @@ -230,8 +240,10 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, return buf; } - /* Skip first address (primary) */ - node = listnextnode(node); + if (family == AF_INET) + uel = ucast_ipv4_encoding_len; + else + uel = ucast_ipv6_encoding_len; /* Scan secondary address list */ curr = buf + 4; /* skip T and L */ @@ -240,8 +252,14 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, struct prefix *p = ifc->address; int l_encode; - if ((curr + ucast_ipv4_encoding_len) > buf_pastend) - return 0; + if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) + continue; + + if ((curr + uel) > buf_pastend) + return 0; + + if (p->family != family) + continue; l_encode = pim_encode_addr_ucast (curr, p); curr += l_encode; @@ -251,7 +269,7 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, if (PIM_DEBUG_PIM_TRACE_DETAIL) { zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu", __PRETTY_FUNCTION__, - option_len / ucast_ipv4_encoding_len); + option_len / uel); } if (option_len < 1) { @@ -491,9 +509,23 @@ pim_parse_addr_ucast (struct prefix *p, p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); - + p->prefixlen = IPV4_MAX_PREFIXLEN; addr += sizeof(struct in_addr); + break; + case PIM_MSG_ADDRESS_FAMILY_IPV6: + if ((addr + sizeof(struct in6_addr)) > pastend) { + zlog_warn ("%s: IPv6 unicast address overflow: left=%zd needed %zu", + __PRETTY_FUNCTION__, + pastend - addr, sizeof(struct in6_addr)); + return -3; + } + + p->family = AF_INET6; + p->prefixlen = IPV6_MAX_PREFIXLEN; + memcpy(&p->u.prefix6, addr, sizeof(struct in6_addr)); + addr += sizeof(struct in6_addr); + break; default: { @@ -706,6 +738,8 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, addr_str, src_str, ifname); } break; + case AF_INET6: + break; default: { 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); return -3; } - p->family = tmp.family; - p->u.prefix4 = tmp.u.prefix4; + prefix_copy(p, &tmp); listnode_add(*hello_option_addr_list, p); } diff --git a/pimd/pim_tlv.h b/pimd/pim_tlv.h index 9c4ebc9f0f..7e0a8a147f 100644 --- a/pimd/pim_tlv.h +++ b/pimd/pim_tlv.h @@ -80,7 +80,8 @@ uint8_t *pim_tlv_append_uint32(uint8_t *buf, uint32_t option_value); uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend, - struct list *ifconnected); + struct list *ifconnected, + int family); int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 172d0d21c9..71634ebfe5 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -198,7 +198,20 @@ pim_upstream_del(struct pim_upstream *up, const char *name) upstream_channel_oil_detach(up); if (up->sources) - list_delete (up->sources); + { + struct listnode *node, *nnode; + struct pim_upstream *child; + for (ALL_LIST_ELEMENTS (up->sources, node, nnode, child)) + { + if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(child->flags)) + { + PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(child->flags); + pim_upstream_del(child, __PRETTY_FUNCTION__); + } + } + + list_delete (up->sources); + } up->sources = NULL; /* @@ -227,8 +240,8 @@ pim_upstream_del(struct pim_upstream *up, const char *name) { char buf[PREFIX2STR_BUFFER]; prefix2str (&nht_p, buf, sizeof (buf)); - zlog_debug ("%s: Deregister upstream %s upstream addr %s with NHT ", - __PRETTY_FUNCTION__, up->sg_str, buf); + zlog_debug ("%s: Deregister upstream %s addr %s with Zebra", + __PRETTY_FUNCTION__, up->sg_str, buf); } pim_delete_tracked_nexthop (&nht_p, up, NULL); @@ -694,10 +707,12 @@ pim_upstream_new (struct prefix_sg *sg, return NULL; } - pim_ifp = up->rpf.source_nexthop.interface->info; - if (pim_ifp) - up->channel_oil = pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index); - + if (up->rpf.source_nexthop.interface) + { + pim_ifp = up->rpf.source_nexthop.interface->info; + if (pim_ifp) + up->channel_oil = pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index); + } listnode_add_sort(pim_upstream_list, up); if (PIM_DEBUG_TRACE) @@ -768,10 +783,14 @@ struct pim_upstream *pim_upstream_add(struct prefix_sg *sg, if (PIM_DEBUG_TRACE) { if (up) - zlog_debug("%s(%s): %s, found: %d: ref_count: %d", + { + char buf[PREFIX2STR_BUFFER]; + prefix2str (&up->rpf.rpf_addr, buf, sizeof (buf)); + zlog_debug("%s(%s): %s, iif %s found: %d: ref_count: %d", __PRETTY_FUNCTION__, name, - up->sg_str, found, + up->sg_str, buf, found, up->ref_count); + } else zlog_debug("%s(%s): (%s) failure to create", __PRETTY_FUNCTION__, name, @@ -1083,26 +1102,31 @@ pim_upstream_keep_alive_timer (struct thread *t) up->t_ka_timer = NULL; if (I_am_RP (up->sg.grp)) - { - pim_br_clear_pmbr (&up->sg); - /* - * We need to do more here :) - * But this is the start. - */ - } + { + pim_br_clear_pmbr (&up->sg); + /* + * We need to do more here :) + * But this is the start. + */ + } /* source is no longer active - pull the SA from MSDP's cache */ pim_msdp_sa_local_del(&up->sg); /* if entry was created because of activity we need to deref it */ if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) - { - pim_upstream_fhr_kat_expiry(up); - if (PIM_DEBUG_TRACE) - zlog_debug ("kat expired on %s; remove stream reference", up->sg_str); - PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags); - pim_upstream_del(up, __PRETTY_FUNCTION__); - } + { + pim_upstream_fhr_kat_expiry(up); + if (PIM_DEBUG_TRACE) + zlog_debug ("kat expired on %s; remove stream reference", up->sg_str); + PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags); + pim_upstream_del(up, __PRETTY_FUNCTION__); + } + else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) + { + PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags); + pim_upstream_del(up, __PRETTY_FUNCTION__); + } return 0; } @@ -1633,28 +1657,67 @@ pim_upstream_sg_running (void *arg) return; } - if (pim_upstream_kat_start_ok(up)) { - /* Add a source reference to the stream if - * one doesn't already exist */ - if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) + if (pim_upstream_kat_start_ok(up)) { - if (PIM_DEBUG_TRACE) - zlog_debug ("source reference created on kat restart %s", up->sg_str); + /* Add a source reference to the stream if + * one doesn't already exist */ + if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) + { + if (PIM_DEBUG_TRACE) + zlog_debug ("source reference created on kat restart %s", up->sg_str); - pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM); - PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags); - pim_upstream_fhr_kat_start(up); + pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM); + PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags); + pim_upstream_fhr_kat_start(up); + } + pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time); } + else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time); - } if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) - { - pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface); - } + { + pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface); + } return; } +void +pim_upstream_add_lhr_star_pimreg (void) +{ + struct pim_upstream *up; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, node, up)) + { + if (up->sg.src.s_addr != INADDR_ANY) + continue; + + if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags)) + continue; + + pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP); + } +} + +void +pim_upstream_remove_lhr_star_pimreg (void) +{ + struct pim_upstream *up; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, node, up)) + { + if (up->sg.src.s_addr != INADDR_ANY) + continue; + + if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags)) + continue; + + pim_channel_del_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP); + } +} + void pim_upstream_init (void) { diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index 6f7556f323..a1af4483ac 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -34,6 +34,8 @@ #define PIM_UPSTREAM_FLAG_MASK_SRC_STREAM (1 << 5) #define PIM_UPSTREAM_FLAG_MASK_SRC_MSDP (1 << 6) #define PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE (1 << 7) +#define PIM_UPSTREAM_FLAG_MASK_SRC_LHR (1 << 8) +#define PIM_UPSTREAM_FLAG_ALL 0xFFFFFFFF #define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) @@ -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_MSDP(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_MSDP) #define PIM_UPSTREAM_FLAG_TEST_SEND_SG_RPT_PRUNE(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE) +#define PIM_UPSTREAM_FLAG_TEST_SRC_LHR(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_LHR) #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) @@ -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_MSDP(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_MSDP) #define PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE) +#define PIM_UPSTREAM_FLAG_SET_SRC_LHR(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_LHR) #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) @@ -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_MSDP(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_MSDP) #define PIM_UPSTREAM_FLAG_UNSET_SEND_SG_RPT_PRUNE(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE) +#define PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_LHR) enum pim_upstream_state { PIM_UPSTREAM_NOTJOINED, @@ -193,4 +198,7 @@ void pim_upstream_terminate (void); void join_timer_start (struct pim_upstream *up); int pim_upstream_compare (void *arg1, void *arg2); void pim_upstream_register_reevaluate (void); + +void pim_upstream_add_lhr_star_pimreg (void); +void pim_upstream_remove_lhr_star_pimreg (void); #endif /* PIM_UPSTREAM_H */ diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index f4bfcc5ce0..ea67039c02 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -150,6 +150,12 @@ int pim_global_config_write(struct vty *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); 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); ++writes; } + if (pimg->spt_switchover == PIM_SPT_INFINITY) + { + vty_out (vty, "ip pim spt-switchover infinity-and-beyond%s", + VTY_NEWLINE); + ++writes; + } if (qpim_ssmpingd_list) { struct listnode *node; diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 4e18c478d6..253ab7ab44 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -258,31 +258,11 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient, #endif } - if (p->family != AF_INET) - { - struct listnode *cnode; - struct connected *conn; - int v4addrs = 0; - - for (ALL_LIST_ELEMENTS_RO (c->ifp->connected, cnode, conn)) - { - if (conn->address->family == AF_INET) - v4addrs++; - } - if (!v4addrs && pim_ifp) - { - pim_ifp->primary_address = pim_find_primary_addr (c->ifp); - pim_if_addr_add_all (c->ifp); - pim_if_add_vif (c->ifp); - } - return 0; - } - if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) { /* trying to add primary address */ struct in_addr primary_addr = pim_find_primary_addr(c->ifp); - if (primary_addr.s_addr != p->u.prefix4.s_addr) { + if (p->family != AF_INET || primary_addr.s_addr != p->u.prefix4.s_addr) { if (PIM_DEBUG_ZEBRA) { /* but we had a primary address already */ @@ -372,6 +352,12 @@ static void scan_upstream_rpf_cache() for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) { enum pim_rpf_result rpf_result; struct pim_rpf old; + struct prefix nht_p; + + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; + pim_resolve_upstream_nh (&nht_p); old.source_nexthop.interface = up->rpf.source_nexthop.interface; old.source_nexthop.nbr = up->rpf.source_nexthop.nbr; @@ -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_events; - pim_rp_setup (); + //It is called as part of pim_neighbor_add + //pim_rp_setup (); return 0; } @@ -836,6 +823,7 @@ void igmp_source_forward_start(struct igmp_source *source) struct igmp_group *group; struct prefix_sg sg; int result; + int input_iface_vif_index = 0; memset (&sg, 0, sizeof (struct prefix_sg)); sg.src = source->source_addr; @@ -861,11 +849,61 @@ void igmp_source_forward_start(struct igmp_source *source) if (!source->source_channel_oil) { struct in_addr vif_source; struct pim_interface *pim_oif; + struct prefix nht_p, src, grp; + int ret = 0; + struct pim_nexthop_cache out_pnc; + struct pim_nexthop nexthop; if (!pim_rp_set_upstream_addr (&vif_source, source->source_addr, sg.grp)) return; - int input_iface_vif_index = fib_lookup_if_vif_index(vif_source); + /* Register addr with Zebra NHT */ + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4 = vif_source; + memset (&out_pnc, 0, sizeof (struct pim_nexthop_cache)); + + if ((ret = pim_find_or_track_nexthop (&nht_p, NULL, NULL, &out_pnc)) == 1) + { + if (out_pnc.nexthop_num) + { + src.family = AF_INET; + src.prefixlen = IPV4_MAX_BITLEN; + src.u.prefix4 = vif_source; //RP or Src address + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = sg.grp; + memset (&nexthop, 0, sizeof (nexthop)); + //Compute PIM RPF using Cached nexthop + pim_ecmp_nexthop_search (&out_pnc, &nexthop, + &src, &grp, 0); + if (nexthop.interface) + input_iface_vif_index = pim_if_find_vifindex_by_ifindex (nexthop.interface->ifindex); + } + else + { + if (PIM_DEBUG_ZEBRA) + { + char buf1[INET_ADDRSTRLEN]; + char buf2[INET_ADDRSTRLEN]; + pim_inet4_dump("", nht_p.u.prefix4, buf1, sizeof(buf1)); + pim_inet4_dump("", 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("", vif_source, buf2, sizeof(buf2)); + zlog_debug ("%s: NHT %s vif_source %s vif_index:%d ", __PRETTY_FUNCTION__, + pim_str_sg_dump (&sg), buf2, input_iface_vif_index); + } + if (input_iface_vif_index < 1) { if (PIM_DEBUG_IGMP_TRACE) { @@ -1013,49 +1051,105 @@ void pim_forward_start(struct pim_ifchannel *ch) { struct pim_upstream *up = ch->upstream; uint32_t mask = PIM_OIF_FLAG_PROTO_PIM; + int input_iface_vif_index = 0; if (PIM_DEBUG_PIM_TRACE) { char source_str[INET_ADDRSTRLEN]; - char group_str[INET_ADDRSTRLEN]; + char group_str[INET_ADDRSTRLEN]; char upstream_str[INET_ADDRSTRLEN]; pim_inet4_dump("", ch->sg.src, source_str, sizeof(source_str)); pim_inet4_dump("", ch->sg.grp, group_str, sizeof(group_str)); pim_inet4_dump("", up->upstream_addr, upstream_str, sizeof(upstream_str)); - zlog_debug("%s: (S,G)=(%s,%s) oif=%s(%s)", + zlog_debug("%s: (S,G)=(%s,%s) oif=%s (%s)", __PRETTY_FUNCTION__, source_str, group_str, ch->interface->name, upstream_str); } - if (!up->channel_oil) { - int input_iface_vif_index = fib_lookup_if_vif_index(up->upstream_addr); - if (input_iface_vif_index < 1) { - if (PIM_DEBUG_PIM_TRACE) - { - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", up->sg.src, source_str, sizeof(source_str)); - zlog_debug("%s %s: could not find input interface for source %s", - __FILE__, __PRETTY_FUNCTION__, - source_str); - } - return; - } + /* Resolve IIF for upstream as mroute_del sets mfcc_parent to MAXVIFS, + as part of mroute_del called by pim_forward_stop. + */ + if (!up->channel_oil || + (up->channel_oil && up->channel_oil->oil.mfcc_parent >= MAXVIFS)) + { + struct prefix nht_p, src, grp; + int ret = 0; + struct pim_nexthop_cache out_pnc; + struct pim_nexthop nexthop; - 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; + /* Register addr with Zebra NHT */ + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = up->sg.grp; + memset (&out_pnc, 0, sizeof (struct pim_nexthop_cache)); + + if ((ret = + pim_find_or_track_nexthop (&nht_p, NULL, NULL, &out_pnc)) == 1) + { + if (out_pnc.nexthop_num) + { + src.family = AF_INET; + src.prefixlen = IPV4_MAX_BITLEN; + src.u.prefix4 = up->upstream_addr; //RP or Src address + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = up->sg.grp; + memset (&nexthop, 0, sizeof (nexthop)); + //Compute PIM RPF using Cached nexthop + pim_ecmp_nexthop_search (&out_pnc, &nexthop, &src, &grp, 0); + input_iface_vif_index = + pim_if_find_vifindex_by_ifindex (nexthop.interface->ifindex); + } + else + { + if (PIM_DEBUG_ZEBRA) + { + char buf1[INET_ADDRSTRLEN]; + char buf2[INET_ADDRSTRLEN]; + pim_inet4_dump("", nht_p.u.prefix4, buf1, sizeof(buf1)); + pim_inet4_dump("", 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("", up->sg.src, source_str, sizeof(source_str)); + zlog_debug("%s %s: could not find input interface for source %s", + __FILE__, __PRETTY_FUNCTION__, + source_str); + } + return; + } + if (PIM_DEBUG_TRACE) + { + zlog_debug ("%s: NHT entry %s update channel_oil vif_index %d ", + __PRETTY_FUNCTION__, up->sg_str, input_iface_vif_index); + } + up->channel_oil = pim_channel_oil_add (&up->sg, input_iface_vif_index); + if (!up->channel_oil) + { + if (PIM_DEBUG_PIM_TRACE) + zlog_debug ("%s %s: could not create OIL for channel (S,G)=%s", + __FILE__, __PRETTY_FUNCTION__, up->sg_str); + return; + } } - } if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP) mask = PIM_OIF_FLAG_PROTO_IGMP; - pim_channel_add_oif(up->channel_oil, ch->interface, mask); + pim_channel_add_oif (up->channel_oil, ch->interface, mask); } void pim_forward_stop(struct pim_ifchannel *ch) diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index f77990ab5a..27bd137043 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -222,6 +222,7 @@ static int zclient_read_nexthop(struct zclient *zlookup, for (i = 0; i < nexthop_num; ++i) { enum nexthop_types_t nexthop_type; struct pim_neighbor *nbr; + struct prefix p; nexthop_type = stream_getc(s); if (num_ifindex >= tab_size) { @@ -251,9 +252,24 @@ static int zclient_read_nexthop(struct zclient *zlookup, break; case NEXTHOP_TYPE_IPV6_IFINDEX: nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET6; - stream_get (&nexthop_tab[num_ifindex].nexthop_addr.u.prefix6, s, 16); + stream_get (&nexthop_tab[num_ifindex].nexthop_addr.u.prefix6, + s, + sizeof(struct in6_addr)); nexthop_tab[num_ifindex].ifindex = stream_getl (s); - nbr = pim_neighbor_find_if (if_lookup_by_index (nexthop_tab[num_ifindex].ifindex, VRF_DEFAULT)); + + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_PREFIXLEN; + memcpy (&p.u.prefix6, + &nexthop_tab[num_ifindex].nexthop_addr.u.prefix6, + sizeof(struct in6_addr)); + + /* + * If we are sending v6 secondary assume we receive v6 secondary + */ + if (pimg->send_v6_secondary) + nbr = pim_neighbor_find_by_secondary(if_lookup_by_index (nexthop_tab[num_ifindex].ifindex, VRF_DEFAULT), &p); + else + nbr = pim_neighbor_find_if (if_lookup_by_index (nexthop_tab[num_ifindex].ifindex, VRF_DEFAULT)); if (nbr) { nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET; diff --git a/pimd/pimd.c b/pimd/pimd.c index bdbd251e20..7b100ffa4e 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -75,7 +75,9 @@ unsigned int qpim_keep_alive_time = PIM_KEEPALIVE_PERIOD; signed int qpim_rp_keep_alive_time = 0; int64_t qpim_nexthop_lookups = 0; int qpim_packet_process = PIM_DEFAULT_PACKET_PROCESS; -struct pim_instance *pimg = NULL; +uint8_t qpim_ecmp_enable = 0; +uint8_t qpim_ecmp_rebalance_enable = 0; +struct pim_instance *pimg = NULL; int32_t qpim_register_suppress_time = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT; int32_t qpim_register_probe_time = PIM_REGISTER_PROBE_TIME_DEFAULT; @@ -115,7 +117,10 @@ pim_vrf_enable (struct vrf *vrf) * We will crash and burn otherwise */ exit(1); - } + } + + pimg->send_v6_secondary = 1; + } return 0; } @@ -249,6 +254,7 @@ pim_instance_init (vrf_id_t vrf_id, afi_t afi) pim->vrf_id = vrf_id; pim->afi = afi; + pim->spt_switchover = PIM_SPT_IMMEDIATE; pim->rpf_hash = hash_create_size (256, pim_rpf_hash_key, pim_rpf_equal); if (PIM_DEBUG_ZEBRA) diff --git a/pimd/pimd.h b/pimd/pimd.h index 69aee28f8f..0db7a7ad16 100644 --- a/pimd/pimd.h +++ b/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 signed int qpim_rp_keep_alive_time; extern int qpim_packet_process; +extern uint8_t qpim_ecmp_enable; +extern uint8_t qpim_ecmp_rebalance_enable; + #define PIM_DEFAULT_PACKET_PROCESS 3 #define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2) @@ -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_INTERNAL (qpim_debugs &= ~PIM_MASK_MSDP_INTERNAL) +enum pim_spt_switchover { + PIM_SPT_IMMEDIATE, + PIM_SPT_INFINITY, +}; + /* Per VRF PIM DB */ struct pim_instance { afi_t afi; vrf_id_t vrf_id; + + enum pim_spt_switchover spt_switchover; + struct hash *rpf_hash; + void *ssm_info; /* per-vrf SSM configuration */ + + int send_v6_secondary; }; extern struct pim_instance *pimg; //Pim Global Instance diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 7fa3baea7e..578c513c78 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -339,7 +339,7 @@ DEFUN (rip_redistribute_type, for(i = 0; redist_type[i].str; i++) { - if (strncmp (redist_type[i].str, argv[2]->arg, + if (strncmp (redist_type[i].str, argv[1]->arg, redist_type[i].str_min_len) == 0) { zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, @@ -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); return CMD_WARNING; @@ -365,7 +365,7 @@ DEFUN (no_rip_redistribute_type, for (i = 0; redist_type[i].str; i++) { - if (strncmp(redist_type[i].str, argv[3]->arg, + if (strncmp(redist_type[i].str, argv[2]->arg, redist_type[i].str_min_len) == 0) { rip_metric_unset (redist_type[i].type, DONT_CARE_METRIC_RIP); @@ -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); return CMD_WARNING; diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 10b98ac4c6..8365030415 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1242,9 +1242,7 @@ DEFUNSH (VTYSH_BGPD, "Layer2 VPN Address family\n" "Ethernet Virtual Private Network Subsequent Address Family\n") { -#if defined(HAVE_EVPN) vty->node = BGP_EVPN_NODE; -#endif /* HAVE_EVPN */ return CMD_SUCCESS; }