]> git.puffer.fish Git - mirror/frr.git/commitdiff
[ospfd] Fix multicast membership drop bug
authorPaul Jakma <paul.jakma@sun.com>
Thu, 15 Jun 2006 18:40:49 +0000 (18:40 +0000)
committerPaul Jakma <paul.jakma@sun.com>
Thu, 15 Jun 2006 18:40:49 +0000 (18:40 +0000)
2006-06-15 Paul Jakma <paul.jakma@sun.com>

* Reported by Milan Koci
* ospf_interface.h: (struct ospf_if_info) Add reference counts
  for multicast group memberships. Add various macros to help
  manipulate/check membership state.
* ospf_interface.c: (ospf_if_set_multicast) Maintain the
  ospf_if_info reference counts, and only actually drop
  memberships if it hits 0, to avoid losing membership when
  OSPF is disabled on an interface with multiple active OSPF
  interfaces.
* ospf_packet.c: (ospf_{hello,read}) Use the new macros to
  check/set
  multicast membership.
* ospf_vty.c: (show_ip_ospf_interface_sub) ditto.

ospfd/ChangeLog
ospfd/ospf_interface.c
ospfd/ospf_interface.h
ospfd/ospf_packet.c
ospfd/ospf_vty.c

index 34d7c4df79c3c272da09013cd6637837252761e5..b7f2c95f5b59db308755cd5ce85384ee58daa012 100644 (file)
@@ -1,3 +1,18 @@
+2006-06-15 Paul Jakma <paul.jakma@sun.com>
+
+       * ospf_interface.h: (struct ospf_if_info) Add reference counts
+         for multicast group memberships. Add various macros to help
+         manipulate/check membership state.
+       * ospf_interface.c: (ospf_if_set_multicast) Maintain the
+         ospf_if_info reference counts, and only actually drop
+         memberships if it hits 0, to avoid losing membership when
+         OSPF is disabled on an interface with multiple active OSPF
+         interfaces.
+       * ospf_packet.c: (ospf_{hello,read}) Use the new macros to
+         check/set
+         multicast membership.
+       * ospf_vty.c: (show_ip_ospf_interface_sub) ditto.
+         
 2006-05-31 Paul Jakma <paul.jakma@sun.com>
 
        * ospf_lsdb.c: (ospf_lsdb_delete) robustify against NULL arguments,
index b94cfa3ac2144cb94f63501a8ed8a0d8fe422abc..2c2c07497ca707db7b726086af3b3abd57587476 100644 (file)
@@ -748,22 +748,25 @@ ospf_if_set_multicast(struct ospf_interface *oi)
       (OSPF_IF_PARAM(oi, passive_interface) == OSPF_IF_ACTIVE))
     {
       /* The interface should belong to the OSPF-all-routers group. */
-      if (!CHECK_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS) &&
+      if (!OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS) &&
          (ospf_if_add_allspfrouters(oi->ospf, oi->address,
                                     oi->ifp->ifindex) >= 0))
-       /* Set the flag only if the system call to join succeeded. */
-        SET_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS);
+         /* Set the flag only if the system call to join succeeded. */
+         OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS);
     }
   else
     {
       /* The interface should NOT belong to the OSPF-all-routers group. */
-      if (CHECK_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS))
+      if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS))
         {
-         ospf_if_drop_allspfrouters (oi->ospf, oi->address, oi->ifp->ifindex);
+          /* Only actually drop if this is the last reference */
+          if (OI_MEMBER_COUNT(oi, MEMBER_ALLROUTERS) == 1)
+           ospf_if_drop_allspfrouters (oi->ospf, oi->address,
+                                       oi->ifp->ifindex);
          /* Unset the flag regardless of whether the system call to leave
             the group succeeded, since it's much safer to assume that
             we are not a member. */
-         UNSET_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS);
+          OI_MEMBER_LEFT(oi,MEMBER_ALLROUTERS);
         }
     }
 
@@ -773,22 +776,25 @@ ospf_if_set_multicast(struct ospf_interface *oi)
       (OSPF_IF_PARAM(oi, passive_interface) == OSPF_IF_ACTIVE))
     {
       /* The interface should belong to the OSPF-designated-routers group. */
-      if (!CHECK_FLAG(oi->multicast_memberships, MEMBER_DROUTERS) &&
+      if (!OI_MEMBER_CHECK(oi, MEMBER_DROUTERS) &&
          (ospf_if_add_alldrouters(oi->ospf, oi->address,
                                   oi->ifp->ifindex) >= 0))
        /* Set the flag only if the system call to join succeeded. */
-        SET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS);
+       OI_MEMBER_JOINED(oi, MEMBER_DROUTERS);
     }
   else
     {
       /* The interface should NOT belong to the OSPF-designated-routers group */
-      if (CHECK_FLAG(oi->multicast_memberships, MEMBER_DROUTERS))
+      if (OI_MEMBER_CHECK(oi, MEMBER_DROUTERS))
         {
-         ospf_if_drop_alldrouters(oi->ospf, oi->address, oi->ifp->ifindex);
+          /* drop only if last reference */
+          if (OI_MEMBER_COUNT(oi, MEMBER_DROUTERS) == 1)
+           ospf_if_drop_alldrouters(oi->ospf, oi->address, oi->ifp->ifindex);
+          
          /* Unset the flag regardless of whether the system call to leave
             the group succeeded, since it's much safer to assume that
             we are not a member. */
-          UNSET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS);
+          OI_MEMBER_LEFT(oi, MEMBER_DROUTERS);
         }
     }
 }
index 3c759405154accd3d5b66149a218ce4ea56fb156..5a825ea5c819d0ada8f27e6d7846b68d95180bca 100644 (file)
@@ -68,11 +68,19 @@ struct ospf_if_params
   DECLARE_IF_PARAM (int, auth_type);               /* OSPF authentication type */
 };
 
+enum
+{
+  MEMBER_ALLROUTERS = 0,
+  MEMBER_DROUTERS,
+  MEMBER_MAX,
+};
+
 struct ospf_if_info
 {
   struct ospf_if_params *def_params;
   struct route_table *params;
   struct route_table *oifs;
+  unsigned int membership_counts[MEMBER_MAX];  /* multicast group refcnts */
 };
 
 struct ospf_interface;
@@ -132,8 +140,20 @@ struct ospf_interface
 
   /* To which multicast groups do we currently belong? */
   u_char multicast_memberships;
-#define MEMBER_ALLROUTERS      0x1
-#define MEMBER_DROUTERS                0x2
+#define OI_MEMBER_FLAG(M) (1 << (M))
+#define OI_MEMBER_COUNT(O,M) (IF_OSPF_IF_INFO(oi->ifp)->membership_counts[(M)])
+#define OI_MEMBER_CHECK(O,M) \
+    (CHECK_FLAG((O)->multicast_memberships, OI_MEMBER_FLAG(M)))
+#define OI_MEMBER_JOINED(O,M) \
+  do { \
+    SET_FLAG ((O)->multicast_memberships, OI_MEMBER_FLAG(M)); \
+    IF_OSPF_IF_INFO((O)->ifp)->membership_counts[(M)]++; \
+  } while (0)
+#define OI_MEMBER_LEFT(O,M) \
+  do { \
+    UNSET_FLAG ((O)->multicast_memberships, OI_MEMBER_FLAG(M)); \
+    IF_OSPF_IF_INFO((O)->ifp)->membership_counts[(M)]--; \
+  } while (0)
 
   struct prefix *address;              /* Interface prefix */
   struct connected *connected;          /* Pointer to connected */ 
index a842ca6856e2a32e70a33e12a7b78f06dfb063b4..569f2513a71f1cad5f184c22550dc71dd7886645 100644 (file)
@@ -768,7 +768,7 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh,
     if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS))
       {
         /* Try to fix multicast membership. */
-        SET_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS);
+        OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS);
         ospf_if_set_multicast(oi);
       }
     return;
@@ -2390,9 +2390,9 @@ ospf_read (struct thread *thread)
                 ifp->name, if_flag_dump(ifp->flags));
       /* Fix multicast memberships? */
       if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS))
-       SET_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS);
+        OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS);
       else if (iph->ip_dst.s_addr == htonl(OSPF_ALLDROUTERS))
-       SET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS);
+       OI_MEMBER_JOINED(oi, MEMBER_DROUTERS);
       if (oi->multicast_memberships)
        ospf_if_set_multicast(oi);
       return 0;
index 8d6ff31fdb1f31949e2bba0ac464c27c2935d22a..10580ab7ca19e546d6d1a663bcef9e41cf04356d 100644 (file)
@@ -2811,12 +2811,15 @@ show_ip_ospf_interface_sub (struct vty *vty, struct ospf *ospf,
        }
 
       vty_out (vty, "  Multicast group memberships:");
-      if (CHECK_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS))
-        vty_out (vty, " OSPFAllRouters");
-      if (CHECK_FLAG(oi->multicast_memberships, MEMBER_DROUTERS))
-        vty_out (vty, " OSPFDesignatedRouters");
-      if (!CHECK_FLAG(oi->multicast_memberships,
-                     MEMBER_ALLROUTERS|MEMBER_DROUTERS))
+      if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS)
+          || OI_MEMBER_CHECK(oi, MEMBER_DROUTERS))
+        {
+          if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS))
+            vty_out (vty, " OSPFAllRouters");
+          if (OI_MEMBER_CHECK(oi, MEMBER_DROUTERS))
+            vty_out (vty, " OSPFDesignatedRouters");
+        }
+      else
         vty_out (vty, " <None>");
       vty_out (vty, "%s", VTY_NEWLINE);