]> git.puffer.fish Git - matthieu/frr.git/commitdiff
pim-anycast-rp: Support in BGP unnumbered networks.
authoranuradhak <anuradhak@cumulusnetworks.com>
Sat, 19 Nov 2016 00:19:26 +0000 (16:19 -0800)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Thu, 22 Dec 2016 01:26:16 +0000 (20:26 -0500)
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 <anuradhak@cumulusnetworks.com>
Acked-by: Donald Sharp <sharpd@cumulusnetworks.com>
pimd/pim_cmd.c
pimd/pim_iface.c
pimd/pim_iface.h
pimd/pim_vty.c
pimd/pimd.h

index 0507ef26814a5a8697cd867009c032db667c9264..ab169434310e6e44ef5670309027fd6e8e648745 100644 (file)
@@ -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);
 }
index fcf07c253a3d004db049f9f4f28e9a83e81497bc..b5f1fadca54295786a49a5cfd3199d947c2a67fd 100644 (file)
@@ -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;
index e2097c870e4dfe63f3fa909d6b7d3db8f099ddae..17bbbd9937fdd24c35972441822343df179e136b 100644 (file)
@@ -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 */
index 527ca5a507d39b80fb2807b3a33cc009df58faee..38cefe7619a1b59bd9418e3d6a9c089eacaa12af 100644 (file)
@@ -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("<src?>", 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);
index 0f4efe91f023723874440a88b400e8a4daffd851..54cecd19d20c8d522f790c829e2423ea4d25ad76 100644 (file)
@@ -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;