diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index b94cfa3..2c2c074 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -748,22 +748,25 @@ ospf_if_set_multicast(struct ospf_interf (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_interf (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); } } } diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index 3c75940..5a825ea 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -68,11 +68,19 @@ #define OSPF_IF_PASSIVE 1 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 @@ #define OSPF_IFTYPE_MAX 7 /* 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 */ diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 7c3be3d..a074244 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2679,6 +2679,18 @@ ospf_discard_from_db (struct ospf *ospf, { struct ospf_lsa *old; + if (!lsdb) + { + zlog_warn ("%s: Called with NULL lsdb!", __func__); + if (!lsa) + zlog_warn ("%s: and NULL LSA!", __func__); + else + zlog_warn ("LSA[Type%d:%s]: not associated with LSDB!", + lsa->data->type, inet_ntoa (lsa->data->id)); + zlog_backtrace (LOG_WARNING); + return; + } + old = ospf_lsdb_lookup (lsdb, lsa); if (!old) @@ -3014,8 +3026,14 @@ #endif /* ORIGINAL_CODING */ } /* Remove from lsdb. */ - ospf_discard_from_db (ospf, lsa->lsdb, lsa); - ospf_lsdb_delete (lsa->lsdb, lsa); + if (lsa->lsdb) + { + ospf_discard_from_db (ospf, lsa->lsdb, lsa); + ospf_lsdb_delete (lsa->lsdb, lsa); + } + else + zlog_warn ("%s: LSA[Type%d:%s]: No associated LSDB!", __func__, + lsa->data->type, inet_ntoa (lsa->data->id)); } /* A MaxAge LSA must be removed immediately from the router's link diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c index c0ec4b3..675e35c 100644 --- a/ospfd/ospf_lsdb.c +++ b/ospfd/ospf_lsdb.c @@ -127,6 +127,24 @@ ospf_lsdb_delete (struct ospf_lsdb *lsdb struct prefix_ls lp; struct route_node *rn; + if (!lsdb) + { + zlog_warn ("%s: Called with NULL LSDB", __func__); + if (lsa) + zlog_warn ("LSA[Type%d:%s]: LSA %p, lsa->lsdb %p", + lsa->data->type, inet_ntoa (lsa->data->id), + lsa, lsa->lsdb); + zlog_backtrace (LOG_WARNING); + return; + } + + if (!lsa) + { + zlog_warn ("%s: Called with NULL LSA", __func__); + zlog_backtrace (LOG_WARNING); + return; + } + table = lsdb->type[lsa->data->type].db; lsdb_prefix_set (&lp, lsa); rn = route_node_lookup (table, (struct prefix *) &lp); diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index a842ca6..569f251 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -768,7 +768,7 @@ ospf_hello (struct ip *iph, struct ospf_ 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; diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 8d6ff31..60ca4c9 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -2811,12 +2811,11 @@ show_ip_ospf_interface_sub (struct vty * } vty_out (vty, " Multicast group memberships:"); - if (CHECK_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS)) + if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS)) vty_out (vty, " OSPFAllRouters"); - if (CHECK_FLAG(oi->multicast_memberships, MEMBER_DROUTERS)) + if (OI_MEMBER_CHECK(oi, MEMBER_DROUTERS)) vty_out (vty, " OSPFDesignatedRouters"); - if (!CHECK_FLAG(oi->multicast_memberships, - MEMBER_ALLROUTERS|MEMBER_DROUTERS)) + else vty_out (vty, " "); vty_out (vty, "%s", VTY_NEWLINE);