123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893 |
- /*
- PIM for Quagga
- Copyright (C) 2008 Everton da Silva Marques
- This program 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 of the License, or
- (at your option) any later version.
- This program 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 this program; see the file COPYING; if not, write to the
- Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- MA 02110-1301 USA
-
- $QuaggaId: $Format:%an, %ai, %h$ $
- */
- #include <zebra.h>
- #include "linklist.h"
- #include "thread.h"
- #include "memory.h"
- #include "pimd.h"
- #include "pim_str.h"
- #include "pim_iface.h"
- #include "pim_ifchannel.h"
- #include "pim_zebra.h"
- #include "pim_time.h"
- #include "pim_msg.h"
- #include "pim_pim.h"
- #include "pim_join.h"
- #include "pim_rpf.h"
- #include "pim_macro.h"
- void pim_ifchannel_free(struct pim_ifchannel *ch)
- {
- zassert(!ch->t_ifjoin_expiry_timer);
- zassert(!ch->t_ifjoin_prune_pending_timer);
- zassert(!ch->t_ifassert_timer);
- XFREE(MTYPE_PIM_IFCHANNEL, ch);
- }
- void pim_ifchannel_delete(struct pim_ifchannel *ch)
- {
- struct pim_interface *pim_ifp;
- pim_ifp = ch->interface->info;
- zassert(pim_ifp);
- if (ch->ifjoin_state != PIM_IFJOIN_NOINFO) {
- pim_upstream_update_join_desired(ch->upstream);
- }
- pim_upstream_del(ch->upstream);
- THREAD_OFF(ch->t_ifjoin_expiry_timer);
- THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
- THREAD_OFF(ch->t_ifassert_timer);
- /*
- notice that listnode_delete() can't be moved
- into pim_ifchannel_free() because the later is
- called by list_delete_all_node()
- */
- listnode_delete(pim_ifp->pim_ifchannel_list, ch);
- pim_ifchannel_free(ch);
- }
- #define IFCHANNEL_NOINFO(ch) \
- ( \
- ((ch)->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO) \
- && \
- ((ch)->ifjoin_state == PIM_IFJOIN_NOINFO) \
- && \
- ((ch)->ifassert_state == PIM_IFASSERT_NOINFO) \
- )
-
- static void delete_on_noinfo(struct pim_ifchannel *ch)
- {
- if (IFCHANNEL_NOINFO(ch)) {
- /* In NOINFO state, timers should have been cleared */
- zassert(!ch->t_ifjoin_expiry_timer);
- zassert(!ch->t_ifjoin_prune_pending_timer);
- zassert(!ch->t_ifassert_timer);
-
- pim_ifchannel_delete(ch);
- }
- }
- void pim_ifchannel_ifjoin_switch(const char *caller,
- struct pim_ifchannel *ch,
- enum pim_ifjoin_state new_state)
- {
- enum pim_ifjoin_state old_state = ch->ifjoin_state;
- if (old_state == new_state) {
- zlog_debug("%s calledby %s: non-transition on state %d (%s)",
- __PRETTY_FUNCTION__, caller, new_state,
- pim_ifchannel_ifjoin_name(new_state));
- return;
- }
- zassert(old_state != new_state);
- ch->ifjoin_state = new_state;
- /* Transition to/from NOINFO ? */
- if (
- (old_state == PIM_IFJOIN_NOINFO)
- ||
- (new_state == PIM_IFJOIN_NOINFO)
- ) {
- if (PIM_DEBUG_PIM_EVENTS) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_debug("PIM_IFCHANNEL_%s: (S,G)=(%s,%s) on interface %s",
- ((new_state == PIM_IFJOIN_NOINFO) ? "DOWN" : "UP"),
- src_str, grp_str, ch->interface->name);
- }
- /*
- Record uptime of state transition to/from NOINFO
- */
- ch->ifjoin_creation = pim_time_monotonic_sec();
- pim_upstream_update_join_desired(ch->upstream);
- pim_ifchannel_update_could_assert(ch);
- pim_ifchannel_update_assert_tracking_desired(ch);
- }
- }
- const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state)
- {
- switch (ifjoin_state) {
- case PIM_IFJOIN_NOINFO: return "NOINFO";
- case PIM_IFJOIN_JOIN: return "JOIN";
- case PIM_IFJOIN_PRUNE_PENDING: return "PRUNEP";
- }
- return "ifjoin_bad_state";
- }
- const char *pim_ifchannel_ifassert_name(enum pim_ifassert_state ifassert_state)
- {
- switch (ifassert_state) {
- case PIM_IFASSERT_NOINFO: return "NOINFO";
- case PIM_IFASSERT_I_AM_WINNER: return "WINNER";
- case PIM_IFASSERT_I_AM_LOSER: return "LOSER";
- }
- return "ifassert_bad_state";
- }
- /*
- RFC 4601: 4.6.5. Assert State Macros
- AssertWinner(S,G,I) defaults to NULL and AssertWinnerMetric(S,G,I)
- defaults to Infinity when in the NoInfo state.
- */
- void reset_ifassert_state(struct pim_ifchannel *ch)
- {
- THREAD_OFF(ch->t_ifassert_timer);
- pim_ifassert_winner_set(ch,
- PIM_IFASSERT_NOINFO,
- qpim_inaddr_any,
- qpim_infinite_assert_metric);
- }
- static struct pim_ifchannel *pim_ifchannel_new(struct interface *ifp,
- struct in_addr source_addr,
- struct in_addr group_addr)
- {
- struct pim_ifchannel *ch;
- struct pim_interface *pim_ifp;
- struct pim_upstream *up;
- pim_ifp = ifp->info;
- zassert(pim_ifp);
- up = pim_upstream_add(source_addr, group_addr);
- if (!up) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
- zlog_err("%s: could not attach upstream (S,G)=(%s,%s) on interface %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str, ifp->name);
- return 0;
- }
- ch = XMALLOC(MTYPE_PIM_IFCHANNEL, sizeof(*ch));
- if (!ch) {
- zlog_err("%s: PIM XMALLOC(%zu) failure",
- __PRETTY_FUNCTION__, sizeof(*ch));
- return 0;
- }
- ch->flags = 0;
- ch->upstream = up;
- ch->interface = ifp;
- ch->source_addr = source_addr;
- ch->group_addr = group_addr;
- ch->local_ifmembership = PIM_IFMEMBERSHIP_NOINFO;
- ch->ifjoin_state = PIM_IFJOIN_NOINFO;
- ch->t_ifjoin_expiry_timer = 0;
- ch->t_ifjoin_prune_pending_timer = 0;
- ch->ifjoin_creation = 0;
- /* Assert state */
- ch->t_ifassert_timer = 0;
- reset_ifassert_state(ch);
- if (pim_macro_ch_could_assert_eval(ch))
- PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags);
- else
- PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags);
- if (pim_macro_assert_tracking_desired_eval(ch))
- PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags);
- else
- PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
- ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch);
- /* Attach to list */
- listnode_add(pim_ifp->pim_ifchannel_list, ch);
- zassert(IFCHANNEL_NOINFO(ch));
- return ch;
- }
- struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp,
- struct in_addr source_addr,
- struct in_addr group_addr)
- {
- struct pim_interface *pim_ifp;
- struct listnode *ch_node;
- struct pim_ifchannel *ch;
- zassert(ifp);
- pim_ifp = ifp->info;
- if (!pim_ifp) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str,
- ifp->name);
- return 0;
- }
- for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
- if (
- (source_addr.s_addr == ch->source_addr.s_addr) &&
- (group_addr.s_addr == ch->group_addr.s_addr)
- ) {
- return ch;
- }
- }
- return 0;
- }
- static void ifmembership_set(struct pim_ifchannel *ch,
- enum pim_ifmembership membership)
- {
- if (ch->local_ifmembership == membership)
- return;
- {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_info("%s: (S,G)=(%s,%s) membership now is %s on interface %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str,
- membership == PIM_IFMEMBERSHIP_INCLUDE ? "INCLUDE" : "NOINFO",
- ch->interface->name);
- }
-
- ch->local_ifmembership = membership;
- pim_upstream_update_join_desired(ch->upstream);
- pim_ifchannel_update_could_assert(ch);
- pim_ifchannel_update_assert_tracking_desired(ch);
- }
- void pim_ifchannel_membership_clear(struct interface *ifp)
- {
- struct pim_interface *pim_ifp;
- struct listnode *ch_node;
- struct pim_ifchannel *ch;
- pim_ifp = ifp->info;
- zassert(pim_ifp);
- for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
- ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
- }
- }
- void pim_ifchannel_delete_on_noinfo(struct interface *ifp)
- {
- struct pim_interface *pim_ifp;
- struct listnode *node;
- struct listnode *next_node;
- struct pim_ifchannel *ch;
- pim_ifp = ifp->info;
- zassert(pim_ifp);
- for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
- delete_on_noinfo(ch);
- }
- }
- struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
- struct in_addr source_addr,
- struct in_addr group_addr)
- {
- struct pim_ifchannel *ch;
- char src_str[100];
- char grp_str[100];
- ch = pim_ifchannel_find(ifp, source_addr, group_addr);
- if (ch)
- return ch;
- ch = pim_ifchannel_new(ifp, source_addr, group_addr);
- if (ch)
- return ch;
-
- pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s: pim_ifchannel_new() failure for (S,G)=(%s,%s) on interface %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str, ifp->name);
- return 0;
- }
- static void ifjoin_to_noinfo(struct pim_ifchannel *ch)
- {
- pim_forward_stop(ch);
- pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_NOINFO);
- delete_on_noinfo(ch);
- }
- static int on_ifjoin_expiry_timer(struct thread *t)
- {
- struct pim_ifchannel *ch;
- zassert(t);
- ch = THREAD_ARG(t);
- zassert(ch);
- ch->t_ifjoin_expiry_timer = 0;
- zassert(ch->ifjoin_state == PIM_IFJOIN_JOIN);
- ifjoin_to_noinfo(ch);
- /* ch may have been deleted */
- return 0;
- }
- static void prune_echo(struct interface *ifp,
- struct in_addr source_addr,
- struct in_addr group_addr)
- {
- struct pim_interface *pim_ifp;
- struct in_addr neigh_dst_addr;
- pim_ifp = ifp->info;
- zassert(pim_ifp);
- neigh_dst_addr = pim_ifp->primary_address;
- if (PIM_DEBUG_PIM_EVENTS) {
- char source_str[100];
- char group_str[100];
- char neigh_dst_str[100];
- pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
- pim_inet4_dump("<neigh?>", neigh_dst_addr, neigh_dst_str, sizeof(neigh_dst_str));
- zlog_debug("%s: sending PruneEcho(S,G)=(%s,%s) to upstream=%s on interface %s",
- __PRETTY_FUNCTION__, source_str, group_str, neigh_dst_str, ifp->name);
- }
- pim_joinprune_send(ifp, neigh_dst_addr, source_addr, group_addr,
- 0 /* boolean: send_join=false (prune) */);
- }
- static int on_ifjoin_prune_pending_timer(struct thread *t)
- {
- struct pim_ifchannel *ch;
- int send_prune_echo; /* boolean */
- struct interface *ifp;
- struct pim_interface *pim_ifp;
- struct in_addr ch_source;
- struct in_addr ch_group;
- zassert(t);
- ch = THREAD_ARG(t);
- zassert(ch);
- ch->t_ifjoin_prune_pending_timer = 0;
- zassert(ch->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING);
- /* Send PruneEcho(S,G) ? */
- ifp = ch->interface;
- pim_ifp = ifp->info;
- send_prune_echo = (listcount(pim_ifp->pim_neighbor_list) > 1);
- /* Save (S,G) */
- ch_source = ch->source_addr;
- ch_group = ch->group_addr;
- ifjoin_to_noinfo(ch);
- /* from here ch may have been deleted */
- if (send_prune_echo)
- prune_echo(ifp, ch_source, ch_group);
- return 0;
- }
- static void check_recv_upstream(int is_join,
- struct interface *recv_ifp,
- struct in_addr upstream,
- struct in_addr source_addr,
- struct in_addr group_addr,
- uint8_t source_flags,
- int holdtime)
- {
- struct pim_upstream *up;
- /* Upstream (S,G) in Joined state ? */
- up = pim_upstream_find(source_addr, group_addr);
- if (!up)
- return;
- if (up->join_state != PIM_UPSTREAM_JOINED)
- return;
- /* Upstream (S,G) in Joined state */
- if (PIM_INADDR_IS_ANY(up->rpf.rpf_addr)) {
- /* RPF'(S,G) not found */
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s %s: RPF'(%s,%s) not found",
- __FILE__, __PRETTY_FUNCTION__,
- src_str, grp_str);
- return;
- }
- /* upstream directed to RPF'(S,G) ? */
- if (upstream.s_addr != up->rpf.rpf_addr.s_addr) {
- char src_str[100];
- char grp_str[100];
- char up_str[100];
- char rpf_str[100];
- pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
- pim_inet4_dump("<up?>", upstream, up_str, sizeof(up_str));
- pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_str, sizeof(rpf_str));
- zlog_warn("%s %s: (S,G)=(%s,%s) upstream=%s not directed to RPF'(S,G)=%s on interface %s",
- __FILE__, __PRETTY_FUNCTION__,
- src_str, grp_str,
- up_str, rpf_str, recv_ifp->name);
- return;
- }
- /* upstream directed to RPF'(S,G) */
- if (is_join) {
- /* Join(S,G) to RPF'(S,G) */
- pim_upstream_join_suppress(up, up->rpf.rpf_addr, holdtime);
- return;
- }
- /* Prune to RPF'(S,G) */
- if (source_flags & PIM_RPT_BIT_MASK) {
- if (source_flags & PIM_WILDCARD_BIT_MASK) {
- /* Prune(*,G) to RPF'(S,G) */
- pim_upstream_join_timer_decrease_to_t_override("Prune(*,G)",
- up, up->rpf.rpf_addr);
- return;
- }
- /* Prune(S,G,rpt) to RPF'(S,G) */
- pim_upstream_join_timer_decrease_to_t_override("Prune(S,G,rpt)",
- up, up->rpf.rpf_addr);
- return;
- }
- /* Prune(S,G) to RPF'(S,G) */
- pim_upstream_join_timer_decrease_to_t_override("Prune(S,G)", up,
- up->rpf.rpf_addr);
- }
- static int nonlocal_upstream(int is_join,
- struct interface *recv_ifp,
- struct in_addr upstream,
- struct in_addr source_addr,
- struct in_addr group_addr,
- uint8_t source_flags,
- uint16_t holdtime)
- {
- struct pim_interface *recv_pim_ifp;
- int is_local; /* boolean */
- recv_pim_ifp = recv_ifp->info;
- zassert(recv_pim_ifp);
- is_local = (upstream.s_addr == recv_pim_ifp->primary_address.s_addr);
-
- if (PIM_DEBUG_PIM_TRACE) {
- char up_str[100];
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
- pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s: recv %s (S,G)=(%s,%s) to %s upstream=%s on %s",
- __PRETTY_FUNCTION__,
- is_join ? "join" : "prune",
- src_str, grp_str,
- is_local ? "local" : "non-local",
- up_str, recv_ifp->name);
- }
- if (is_local)
- return 0;
- /*
- Since recv upstream addr was not directed to our primary
- address, check if we should react to it in any way.
- */
- check_recv_upstream(is_join, recv_ifp, upstream, source_addr, group_addr,
- source_flags, holdtime);
- return 1; /* non-local */
- }
- void pim_ifchannel_join_add(struct interface *ifp,
- struct in_addr neigh_addr,
- struct in_addr upstream,
- struct in_addr source_addr,
- struct in_addr group_addr,
- uint8_t source_flags,
- uint16_t holdtime)
- {
- struct pim_interface *pim_ifp;
- struct pim_ifchannel *ch;
- if (nonlocal_upstream(1 /* join */, ifp, upstream,
- source_addr, group_addr, source_flags, holdtime)) {
- return;
- }
- ch = pim_ifchannel_add(ifp, source_addr, group_addr);
- if (!ch)
- return;
- /*
- RFC 4601: 4.6.1. (S,G) Assert Message State Machine
- Transitions from "I am Assert Loser" State
- Receive Join(S,G) on Interface I
- We receive a Join(S,G) that has the Upstream Neighbor Address
- field set to my primary IP address on interface I. The action is
- to transition to NoInfo state, delete this (S,G) assert state
- (Actions A5 below), and allow the normal PIM Join/Prune mechanisms
- to operate.
- Notice: The nonlocal_upstream() test above ensures the upstream
- address of the join message is our primary address.
- */
- if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
- char src_str[100];
- char grp_str[100];
- char neigh_str[100];
- pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
- pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
- zlog_warn("%s: Assert Loser recv Join(%s,%s) from %s on %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str, neigh_str, ifp->name);
- assert_action_a5(ch);
- }
- pim_ifp = ifp->info;
- zassert(pim_ifp);
- switch (ch->ifjoin_state) {
- case PIM_IFJOIN_NOINFO:
- pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN);
- if (pim_macro_chisin_oiflist(ch)) {
- pim_forward_start(ch);
- }
- break;
- case PIM_IFJOIN_JOIN:
- zassert(!ch->t_ifjoin_prune_pending_timer);
- /*
- In the JOIN state ch->t_ifjoin_expiry_timer may be NULL due to a
- previously received join message with holdtime=0xFFFF.
- */
- if (ch->t_ifjoin_expiry_timer) {
- unsigned long remain =
- thread_timer_remain_second(ch->t_ifjoin_expiry_timer);
- if (remain > holdtime) {
- /*
- RFC 4601: 4.5.3. Receiving (S,G) Join/Prune Messages
- Transitions from Join State
- The (S,G) downstream state machine on interface I remains in
- Join state, and the Expiry Timer (ET) is restarted, set to
- maximum of its current value and the HoldTime from the
- triggering Join/Prune message.
- Conclusion: Do not change the ET if the current value is
- higher than the received join holdtime.
- */
- return;
- }
- }
- THREAD_OFF(ch->t_ifjoin_expiry_timer);
- break;
- case PIM_IFJOIN_PRUNE_PENDING:
- zassert(!ch->t_ifjoin_expiry_timer);
- zassert(ch->t_ifjoin_prune_pending_timer);
- THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
- pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN);
- break;
- }
- zassert(!IFCHANNEL_NOINFO(ch));
- if (holdtime != 0xFFFF) {
- THREAD_TIMER_ON(master, ch->t_ifjoin_expiry_timer,
- on_ifjoin_expiry_timer,
- ch, holdtime);
- }
- }
- void pim_ifchannel_prune(struct interface *ifp,
- struct in_addr upstream,
- struct in_addr source_addr,
- struct in_addr group_addr,
- uint8_t source_flags,
- uint16_t holdtime)
- {
- struct pim_ifchannel *ch;
- int jp_override_interval_msec;
- if (nonlocal_upstream(0 /* prune */, ifp, upstream,
- source_addr, group_addr, source_flags, holdtime)) {
- return;
- }
- ch = pim_ifchannel_add(ifp, source_addr, group_addr);
- if (!ch)
- return;
- switch (ch->ifjoin_state) {
- case PIM_IFJOIN_NOINFO:
- case PIM_IFJOIN_PRUNE_PENDING:
- /* nothing to do */
- break;
- case PIM_IFJOIN_JOIN:
- {
- struct pim_interface *pim_ifp;
- pim_ifp = ifp->info;
- zassert(ch->t_ifjoin_expiry_timer);
- zassert(!ch->t_ifjoin_prune_pending_timer);
- THREAD_OFF(ch->t_ifjoin_expiry_timer);
-
- pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_PRUNE_PENDING);
-
- if (listcount(pim_ifp->pim_neighbor_list) > 1) {
- jp_override_interval_msec = pim_if_jp_override_interval_msec(ifp);
- }
- else {
- jp_override_interval_msec = 0; /* schedule to expire immediately */
- /* If we called ifjoin_prune() directly instead, care should
- be taken not to use "ch" afterwards since it would be
- deleted. */
- }
-
- THREAD_TIMER_MSEC_ON(master, ch->t_ifjoin_prune_pending_timer,
- on_ifjoin_prune_pending_timer,
- ch, jp_override_interval_msec);
-
- zassert(!ch->t_ifjoin_expiry_timer);
- zassert(ch->t_ifjoin_prune_pending_timer);
- }
- break;
- }
- }
- void pim_ifchannel_local_membership_add(struct interface *ifp,
- struct in_addr source_addr,
- struct in_addr group_addr)
- {
- struct pim_ifchannel *ch;
- struct pim_interface *pim_ifp;
- /* PIM enabled on interface? */
- pim_ifp = ifp->info;
- if (!pim_ifp)
- return;
- if (!PIM_IF_TEST_PIM(pim_ifp->options))
- return;
- ch = pim_ifchannel_add(ifp, source_addr, group_addr);
- if (!ch) {
- return;
- }
- ifmembership_set(ch, PIM_IFMEMBERSHIP_INCLUDE);
- zassert(!IFCHANNEL_NOINFO(ch));
- }
- void pim_ifchannel_local_membership_del(struct interface *ifp,
- struct in_addr source_addr,
- struct in_addr group_addr)
- {
- struct pim_ifchannel *ch;
- struct pim_interface *pim_ifp;
- /* PIM enabled on interface? */
- pim_ifp = ifp->info;
- if (!pim_ifp)
- return;
- if (!PIM_IF_TEST_PIM(pim_ifp->options))
- return;
- ch = pim_ifchannel_find(ifp, source_addr, group_addr);
- if (!ch)
- return;
- ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
- delete_on_noinfo(ch);
- }
- void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch)
- {
- int old_couldassert = PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags));
- int new_couldassert = PIM_FORCE_BOOLEAN(pim_macro_ch_could_assert_eval(ch));
- if (new_couldassert == old_couldassert)
- return;
- {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_info("%s: CouldAssert(%s,%s,%s) changed from %d to %d",
- __PRETTY_FUNCTION__,
- src_str, grp_str, ch->interface->name,
- old_couldassert, new_couldassert);
- }
- if (new_couldassert) {
- /* CouldAssert(S,G,I) switched from FALSE to TRUE */
- PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags);
- }
- else {
- /* CouldAssert(S,G,I) switched from TRUE to FALSE */
- PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags);
- if (ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER) {
- assert_action_a4(ch);
- }
- }
- pim_ifchannel_update_my_assert_metric(ch);
- }
- /*
- my_assert_metric may be affected by:
- CouldAssert(S,G)
- pim_ifp->primary_address
- rpf->source_nexthop.mrib_metric_preference;
- rpf->source_nexthop.mrib_route_metric;
- */
- void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch)
- {
- struct pim_assert_metric my_metric_new = pim_macro_ch_my_assert_metric_eval(ch);
- if (pim_assert_metric_match(&my_metric_new, &ch->ifassert_my_metric))
- return;
- {
- char src_str[100];
- char grp_str[100];
- char old_addr_str[100];
- char new_addr_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- pim_inet4_dump("<old_addr?>", ch->ifassert_my_metric.ip_address, old_addr_str, sizeof(old_addr_str));
- pim_inet4_dump("<new_addr?>", my_metric_new.ip_address, new_addr_str, sizeof(new_addr_str));
- zlog_info("%s: my_assert_metric(%s,%s,%s) changed from %u,%u,%u,%s to %u,%u,%u,%s",
- __PRETTY_FUNCTION__,
- src_str, grp_str, ch->interface->name,
- ch->ifassert_my_metric.rpt_bit_flag,
- ch->ifassert_my_metric.metric_preference,
- ch->ifassert_my_metric.route_metric,
- old_addr_str,
- my_metric_new.rpt_bit_flag,
- my_metric_new.metric_preference,
- my_metric_new.route_metric,
- new_addr_str);
- }
- ch->ifassert_my_metric = my_metric_new;
- if (pim_assert_metric_better(&ch->ifassert_my_metric,
- &ch->ifassert_winner_metric)) {
- assert_action_a5(ch);
- }
- }
- void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch)
- {
- int old_atd = PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags));
- int new_atd = PIM_FORCE_BOOLEAN(pim_macro_assert_tracking_desired_eval(ch));
- if (new_atd == old_atd)
- return;
- {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_info("%s: AssertTrackingDesired(%s,%s,%s) changed from %d to %d",
- __PRETTY_FUNCTION__,
- src_str, grp_str, ch->interface->name,
- old_atd, new_atd);
- }
- if (new_atd) {
- /* AssertTrackingDesired(S,G,I) switched from FALSE to TRUE */
- PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags);
- }
- else {
- /* AssertTrackingDesired(S,G,I) switched from TRUE to FALSE */
- PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
- if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
- assert_action_a5(ch);
- }
- }
- }
|