From 4763cd0ed51565db9bc32eeadee8b91c12eb3623 Mon Sep 17 00:00:00 2001 From: anuradhak Date: Fri, 18 Nov 2016 16:19:26 -0800 Subject: [PATCH] pim-anycast-rp: Support in BGP unnumbered networks. Anycast rp requires multiple ip addresses on the lo. If PIM is used in an unnumbered BGP network it picks one of the lo addresses as the pim-primary for the swp interfaces. But if the anycast IP is picked up by both sides pim nbr will never converge. So a static "use-source" config is provided to allow the administrator to force the the hello source to the unique IP address. Sample output: ============= dell-s6000-04(config-if)# do show running-config pimd >>>>>> SNIPPED >>>>>>>>>>>>>>>>> interface lo ip pim sm ip pim use-source 100.1.1.5 ! >>>>>> SNIPPED >>>>>>>>>>>>>>>>> dell-s6000-04(config-if)# do show ip pim interface lo Interface : lo State : up Use Source : 100.1.1.5 Address : 100.1.1.5 (primary) 100.1.1.100 >>>>>> SNIPPED >>>>>>>>>>>>>>>>> dell-s6000-04(config-if)# do show ip pim interface lo json { "lo":{ "name":"lo", "state":"up", "address":"100.1.1.5", "index":1, "lanDelayEnabled":true, "useSource":"100.1.1.5", "secondaryAddressList":[ "100.1.1.100" ], >>>>>> SNIPPED >>>>>>>>>>>>>>>>> Signed-off-by: Anuradha Karuppiah Acked-by: Donald Sharp --- pimd/pim_cmd.c | 68 +++++++++++++++++++++++++++++++++++--- pimd/pim_iface.c | 85 ++++++++++++++++++++++++++++-------------------- pimd/pim_iface.h | 3 ++ pimd/pim_vty.c | 9 +++++ pimd/pimd.h | 2 ++ 5 files changed, 126 insertions(+), 41 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 0507ef2681..ab16943431 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -820,6 +820,9 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, u_ch json_row = json_object_new_object(); json_object_pim_ifp_add(json_row, ifp); + if (pim_ifp->update_source.s_addr != INADDR_ANY) { + json_object_string_add(json_row, "useSource", inet_ntoa(pim_ifp->update_source)); + } if (pim_ifp->sec_addr_list) { json_object *sec_list = NULL; @@ -910,17 +913,20 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, u_ch json_object_object_add(json, ifp->name, json_row); } else { - vty_out(vty, "Interface : %s%s", ifp->name, VTY_NEWLINE); - vty_out(vty, "State : %s%s", if_is_up(ifp) ? "up" : "down", VTY_NEWLINE); + vty_out(vty, "Interface : %s%s", ifp->name, VTY_NEWLINE); + vty_out(vty, "State : %s%s", if_is_up(ifp) ? "up" : "down", VTY_NEWLINE); + if (pim_ifp->update_source.s_addr != INADDR_ANY) { + vty_out(vty, "Use Source : %s%s", inet_ntoa(pim_ifp->update_source), VTY_NEWLINE); + } if (pim_ifp->sec_addr_list) { - vty_out(vty, "Address : %s (primary)%s", + vty_out(vty, "Address : %s (primary)%s", inet_ntoa(ifaddr), VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, sec_node, sec_addr)) { - vty_out(vty, " %s%s", + vty_out(vty, " %s%s", inet_ntoa(sec_addr->addr), VTY_NEWLINE); } } else { - vty_out(vty, "Address : %s%s", inet_ntoa(ifaddr), VTY_NEWLINE); + vty_out(vty, "Address : %s%s", inet_ntoa(ifaddr), VTY_NEWLINE); } vty_out(vty, "%s", VTY_NEWLINE); @@ -5186,6 +5192,56 @@ DEFUN (show_debugging_pim, return CMD_SUCCESS; } +static int +interface_pim_use_src_cmd_worker(struct vty *vty, const char *source) +{ + int result; + struct in_addr source_addr; + VTY_DECLVAR_CONTEXT(interface, ifp); + + result = inet_pton(AF_INET, source, &source_addr); + if (result <= 0) { + vty_out(vty, "%% Bad source address %s: errno=%d: %s%s", + source, errno, safe_strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + result = pim_update_source_set(ifp, source_addr); + switch (result) { + case PIM_SUCCESS: + break; + case PIM_UPDATE_SOURCE_DUP: + vty_out(vty, "%% Source already set to %s%s", source, VTY_NEWLINE); + break; + default: + vty_out(vty, "%% Source set failed%s", VTY_NEWLINE); + } + + return result?CMD_WARNING:CMD_SUCCESS; +} + +DEFUN (interface_pim_use_source, + interface_pim_use_source_cmd, + "ip pim use-source A.B.C.D", + IP_STR + "pim multicast routing\n" + "Configure primary IP address\n" + "source ip address\n") +{ + return interface_pim_use_src_cmd_worker (vty, argv[3]->arg); +} + +DEFUN (interface_no_pim_use_source, + interface_no_pim_use_source_cmd, + "no ip pim use-source", + NO_STR + IP_STR + "pim multicast routing\n" + "Delete source IP address\n") +{ + return interface_pim_use_src_cmd_worker (vty, "0.0.0.0"); +} + static int ip_msdp_peer_cmd_worker (struct vty *vty, const char *peer, const char *local) { @@ -6145,4 +6201,6 @@ void pim_cmd_init() install_element (VIEW_NODE, &show_ip_msdp_sa_detail_cmd); install_element (VIEW_NODE, &show_ip_msdp_sa_sg_cmd); install_element (VIEW_NODE, &show_ip_msdp_mesh_group_cmd); + install_element (INTERFACE_NODE, &interface_pim_use_source_cmd); + install_element (INTERFACE_NODE, &interface_no_pim_use_source_cmd); } diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index fcf07c253a..b5f1fadca5 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -267,14 +267,10 @@ static int detect_primary_address_change(struct interface *ifp, int force_prim_as_any, const char *caller) { - struct pim_interface *pim_ifp; + struct pim_interface *pim_ifp = ifp->info; struct in_addr new_prim_addr; int changed; - pim_ifp = ifp->info; - if (!pim_ifp) - return 0; - if (force_prim_as_any) new_prim_addr = qpim_inaddr_any; else @@ -295,12 +291,6 @@ static int detect_primary_address_change(struct interface *ifp, if (changed) { pim_ifp->primary_address = new_prim_addr; - - if (!PIM_IF_TEST_PIM(pim_ifp->options)) { - return changed; - } - - pim_addr_change(ifp); } return changed; @@ -457,56 +447,74 @@ static int pim_sec_addr_update(struct interface *ifp) return changed; } -static void detect_secondary_address_change(struct interface *ifp, +static int detect_secondary_address_change(struct interface *ifp, int force_prim_as_any, const char *caller) { - struct pim_interface *pim_ifp; + struct pim_interface *pim_ifp = ifp->info; int changed = 0; - pim_ifp = ifp->info; - if (!pim_ifp) - return; - if (force_prim_as_any) { /* if primary address is being forced to zero just flush the * secondary address list */ - pim_sec_addr_del_all(pim_ifp); + changed = pim_sec_addr_del_all(pim_ifp); } else { /* re-evaluate the secondary address list */ changed = pim_sec_addr_update(ifp); } - if (PIM_DEBUG_ZEBRA) - zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change", - __PRETTY_FUNCTION__, ifp->name); + return changed; +} + +static void detect_address_change(struct interface *ifp, + int force_prim_as_any, + const char *caller) +{ + int changed = 0; + struct pim_interface *pim_ifp; - if (!changed) { + pim_ifp = ifp->info; + if (!pim_ifp) return; + + if (detect_primary_address_change(ifp, force_prim_as_any, caller)) { + changed = 1; } - if (!PIM_IF_TEST_PIM(pim_ifp->options)) { - return; + if (detect_secondary_address_change(ifp, force_prim_as_any, caller)) { + changed = 1; + } + + + if (changed) { + if (!PIM_IF_TEST_PIM(pim_ifp->options)) { + return; + } + + pim_addr_change(ifp); } - /* XXX - re-evaluate i_am_rp on addr change */ - //pim_addr_change(ifp); + /* XXX: if we have unnumbered interfaces we need to run detect address + * address change on all of them when the lo address changes */ } -static void detect_address_change(struct interface *ifp, - int force_prim_as_any, - const char *caller) +int pim_update_source_set(struct interface *ifp, struct in_addr source) { - int prim_changed; + struct pim_interface *pim_ifp = ifp->info; - prim_changed = detect_primary_address_change(ifp, force_prim_as_any, caller); - if (prim_changed) { - /* no need to detect secondary change because - the reaction would be the same */ - return; + if (!pim_ifp) { + return PIM_IFACE_NOT_FOUND; } - detect_secondary_address_change(ifp, force_prim_as_any, caller); + if (pim_ifp->update_source.s_addr == source.s_addr) { + return PIM_UPDATE_SOURCE_DUP; + } + + pim_ifp->update_source = source; + detect_address_change(ifp, 0 /* force_prim_as_any */, + __PRETTY_FUNCTION__); + + return PIM_SUCCESS; } void pim_if_addr_add(struct connected *ifc) @@ -780,6 +788,11 @@ pim_find_primary_addr (struct interface *ifp) struct in_addr addr; int v4_addrs = 0; int v6_addrs = 0; + struct pim_interface *pim_ifp = ifp->info; + + if (pim_ifp && PIM_INADDR_ISNOT_ANY(pim_ifp->update_source)) { + return pim_ifp->update_source; + } for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { struct prefix *p = ifc->address; diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index e2097c870e..17bbbd9937 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -75,6 +75,8 @@ struct pim_interface { ifindex_t mroute_vif_index; struct in_addr primary_address; /* remember addr to detect change */ struct list *sec_addr_list; /* list of struct pim_secondary_addr */ + struct in_addr update_source; /* user can statically set the primary + * address of the interface */ int igmp_version; /* IGMP version */ int igmp_default_robustness_variable; /* IGMPv3 QRV */ @@ -185,5 +187,6 @@ void pim_if_update_assert_tracking_desired(struct interface *ifp); void pim_if_create_pimreg(void); int pim_if_connected_to_source (struct interface *ifp, struct in_addr src); +int pim_update_source_set(struct interface *ifp, struct in_addr source); #endif /* PIM_IFACE_H */ diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 527ca5a507..38cefe7619 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -230,6 +230,15 @@ int pim_interface_config_write(struct vty *vty) vty_out(vty, "%s", VTY_NEWLINE); } + /* update source */ + if (PIM_INADDR_ISNOT_ANY(pim_ifp->update_source)) { + char src_str[INET_ADDRSTRLEN]; + pim_inet4_dump("", pim_ifp->update_source, src_str, + sizeof(src_str)); + vty_out(vty, " ip pim use-source %s%s", src_str, VTY_NEWLINE); + ++writes; + } + /* IF ip igmp */ if (PIM_IF_TEST_IGMP(pim_ifp->options)) { vty_out(vty, " ip igmp%s", VTY_NEWLINE); diff --git a/pimd/pimd.h b/pimd/pimd.h index 0f4efe91f0..54cecd19d2 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -86,6 +86,8 @@ #define PIM_RP_NO_PATH -6 #define PIM_RP_NOT_FOUND -7 #define PIM_RP_PFXLIST_IN_USE -8 +#define PIM_IFACE_NOT_FOUND -9 +#define PIM_UPDATE_SOURCE_DUP -10 const char *const PIM_ALL_SYSTEMS; const char *const PIM_ALL_ROUTERS; -- 2.39.5