123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808 |
- /*
- 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 "log.h"
- #include "prefix.h"
- #include "pimd.h"
- #include "pim_str.h"
- #include "pim_tlv.h"
- #include "pim_msg.h"
- #include "pim_pim.h"
- #include "pim_int.h"
- #include "pim_time.h"
- #include "pim_iface.h"
- #include "pim_hello.h"
- #include "pim_macro.h"
- #include "pim_assert.h"
- #include "pim_ifchannel.h"
- static int assert_action_a3(struct pim_ifchannel *ch);
- static void assert_action_a2(struct pim_ifchannel *ch,
- struct pim_assert_metric winner_metric);
- static void assert_action_a6(struct pim_ifchannel *ch,
- struct pim_assert_metric winner_metric);
- void pim_ifassert_winner_set(struct pim_ifchannel *ch,
- enum pim_ifassert_state new_state,
- struct in_addr winner,
- struct pim_assert_metric winner_metric)
- {
- int winner_changed = (ch->ifassert_winner.s_addr != winner.s_addr);
- int metric_changed = !pim_assert_metric_match(&ch->ifassert_winner_metric,
- &winner_metric);
- if (PIM_DEBUG_PIM_EVENTS) {
- if (ch->ifassert_state != new_state) {
- 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("%s: (S,G)=(%s,%s) assert state changed from %s to %s on interface %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str,
- pim_ifchannel_ifassert_name(ch->ifassert_state),
- pim_ifchannel_ifassert_name(new_state),
- ch->interface->name);
- }
- if (winner_changed) {
- char src_str[100];
- char grp_str[100];
- char was_str[100];
- char winner_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("<was?>", ch->ifassert_winner, was_str, sizeof(was_str));
- pim_inet4_dump("<winner?>", winner, winner_str, sizeof(winner_str));
- zlog_debug("%s: (S,G)=(%s,%s) assert winner changed from %s to %s on interface %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str,
- was_str, winner_str, ch->interface->name);
- }
- } /* PIM_DEBUG_PIM_EVENTS */
- ch->ifassert_state = new_state;
- ch->ifassert_winner = winner;
- ch->ifassert_winner_metric = winner_metric;
- ch->ifassert_creation = pim_time_monotonic_sec();
- if (winner_changed || metric_changed) {
- pim_upstream_update_join_desired(ch->upstream);
- pim_ifchannel_update_could_assert(ch);
- pim_ifchannel_update_assert_tracking_desired(ch);
- }
- }
- static void on_trace(const char *label,
- struct interface *ifp, struct in_addr src)
- {
- if (PIM_DEBUG_PIM_TRACE) {
- char src_str[100];
- pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
- zlog_debug("%s: from %s on %s",
- label, src_str, ifp->name);
- }
- }
- static int preferred_assert(const struct pim_ifchannel *ch,
- const struct pim_assert_metric *recv_metric)
- {
- return pim_assert_metric_better(recv_metric,
- &ch->ifassert_winner_metric);
- }
- static int acceptable_assert(const struct pim_assert_metric *my_metric,
- const struct pim_assert_metric *recv_metric)
- {
- return pim_assert_metric_better(recv_metric,
- my_metric);
- }
- static int inferior_assert(const struct pim_assert_metric *my_metric,
- const struct pim_assert_metric *recv_metric)
- {
- return pim_assert_metric_better(my_metric,
- recv_metric);
- }
- static int cancel_assert(const struct pim_assert_metric *recv_metric)
- {
- return (recv_metric->metric_preference == PIM_ASSERT_METRIC_PREFERENCE_MAX)
- &&
- (recv_metric->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX);
- }
- static void if_could_assert_do_a1(const char *caller,
- struct pim_ifchannel *ch)
- {
- if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
- if (assert_action_a1(ch)) {
- 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_warn("%s: %s: (S,G)=(%s,%s) assert_action_a1 failure on interface %s",
- __PRETTY_FUNCTION__, caller,
- src_str, grp_str, ch->interface->name);
- /* log warning only */
- }
- }
- }
- static int dispatch_assert(struct interface *ifp,
- struct in_addr source_addr,
- struct in_addr group_addr,
- struct pim_assert_metric recv_metric)
- {
- struct pim_ifchannel *ch;
- ch = pim_ifchannel_add(ifp, source_addr, group_addr);
- if (!ch) {
- char source_str[100];
- char group_str[100];
- pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
- zlog_warn("%s: (S,G)=(%s,%s) failure creating channel on interface %s",
- __PRETTY_FUNCTION__,
- source_str, group_str, ifp->name);
- return -1;
- }
- switch (ch->ifassert_state) {
- case PIM_IFASSERT_NOINFO:
- if (recv_metric.rpt_bit_flag) {
- /* RPT bit set */
- if_could_assert_do_a1(__PRETTY_FUNCTION__, ch);
- }
- else {
- /* RPT bit clear */
- if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
- if_could_assert_do_a1(__PRETTY_FUNCTION__, ch);
- }
- else if (acceptable_assert(&ch->ifassert_my_metric, &recv_metric)) {
- if (PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags)) {
- assert_action_a6(ch, recv_metric);
- }
- }
- }
- break;
- case PIM_IFASSERT_I_AM_WINNER:
- if (preferred_assert(ch, &recv_metric)) {
- assert_action_a2(ch, recv_metric);
- }
- else {
- if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
- zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
- assert_action_a3(ch);
- }
- }
- break;
- case PIM_IFASSERT_I_AM_LOSER:
- if (recv_metric.ip_address.s_addr == ch->ifassert_winner.s_addr) {
- /* Assert from current winner */
- if (cancel_assert(&recv_metric)) {
- assert_action_a5(ch);
- }
- else {
- if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
- assert_action_a5(ch);
- }
- else if (acceptable_assert(&ch->ifassert_my_metric, &recv_metric)) {
- if (!recv_metric.rpt_bit_flag) {
- assert_action_a2(ch, recv_metric);
- }
- }
- }
- }
- else if (preferred_assert(ch, &recv_metric)) {
- assert_action_a2(ch, recv_metric);
- }
- break;
- default:
- {
- char source_str[100];
- char group_str[100];
- pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
- zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s",
- __PRETTY_FUNCTION__,
- source_str, group_str, ch->ifassert_state, ifp->name);
- }
- return -2;
- }
- return 0;
- }
- int pim_assert_recv(struct interface *ifp,
- struct pim_neighbor *neigh,
- struct in_addr src_addr,
- uint8_t *buf, int buf_size)
- {
- struct prefix msg_group_addr;
- struct prefix msg_source_addr;
- struct pim_assert_metric msg_metric;
- int offset;
- uint8_t *curr;
- int curr_size;
- on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
- curr = buf;
- curr_size = buf_size;
- /*
- Parse assert group addr
- */
- offset = pim_parse_addr_group(ifp->name, src_addr,
- &msg_group_addr,
- curr, curr_size);
- if (offset < 1) {
- char src_str[100];
- pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
- zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s",
- __PRETTY_FUNCTION__,
- src_str, ifp->name);
- return -1;
- }
- curr += offset;
- curr_size -= offset;
- /*
- Parse assert source addr
- */
- offset = pim_parse_addr_ucast(ifp->name, src_addr,
- &msg_source_addr,
- curr, curr_size);
- if (offset < 1) {
- char src_str[100];
- pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
- zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
- __PRETTY_FUNCTION__,
- src_str, ifp->name);
- return -2;
- }
- curr += offset;
- curr_size -= offset;
- if (curr_size != 8) {
- char src_str[100];
- pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
- zlog_warn("%s: preference/metric size is not 8: size=%d from %s on interface %s",
- __PRETTY_FUNCTION__,
- curr_size,
- src_str, ifp->name);
- return -3;
- }
- /*
- Parse assert metric preference
- */
- msg_metric.metric_preference = pim_read_uint32_host(curr);
- msg_metric.rpt_bit_flag = msg_metric.metric_preference & 0x80000000; /* save highest bit */
- msg_metric.metric_preference &= ~0x80000000; /* clear highest bit */
- curr += 4;
- /*
- Parse assert route metric
- */
- msg_metric.route_metric = pim_read_uint32_host(curr);
- if (PIM_DEBUG_PIM_TRACE) {
- char neigh_str[100];
- char source_str[100];
- char group_str[100];
- pim_inet4_dump("<neigh?>", src_addr, neigh_str, sizeof(neigh_str));
- pim_inet4_dump("<src?>", msg_source_addr.u.prefix4, source_str, sizeof(source_str));
- pim_inet4_dump("<grp?>", msg_group_addr.u.prefix4, group_str, sizeof(group_str));
- zlog_debug("%s: from %s on %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
- __PRETTY_FUNCTION__, neigh_str, ifp->name,
- source_str, group_str,
- msg_metric.metric_preference,
- msg_metric.route_metric,
- PIM_FORCE_BOOLEAN(msg_metric.rpt_bit_flag));
- }
- msg_metric.ip_address = src_addr;
- return dispatch_assert(ifp,
- msg_source_addr.u.prefix4,
- msg_group_addr.u.prefix4,
- msg_metric);
- }
- /*
- RFC 4601: 4.6.3. Assert Metrics
- Assert metrics are defined as:
- When comparing assert_metrics, the rpt_bit_flag, metric_preference,
- and route_metric field are compared in order, where the first lower
- value wins. If all fields are equal, the primary IP address of the
- router that sourced the Assert message is used as a tie-breaker,
- with the highest IP address winning.
- */
- int pim_assert_metric_better(const struct pim_assert_metric *m1,
- const struct pim_assert_metric *m2)
- {
- if (m1->rpt_bit_flag < m2->rpt_bit_flag)
- return 1;
- if (m1->rpt_bit_flag > m2->rpt_bit_flag)
- return 0;
- if (m1->metric_preference < m2->metric_preference)
- return 1;
- if (m1->metric_preference > m2->metric_preference)
- return 0;
- if (m1->route_metric < m2->route_metric)
- return 1;
- if (m1->route_metric > m2->route_metric)
- return 0;
- return ntohl(m1->ip_address.s_addr) > ntohl(m2->ip_address.s_addr);
- }
- int pim_assert_metric_match(const struct pim_assert_metric *m1,
- const struct pim_assert_metric *m2)
- {
- if (m1->rpt_bit_flag != m2->rpt_bit_flag)
- return 0;
- if (m1->metric_preference != m2->metric_preference)
- return 0;
- if (m1->route_metric != m2->route_metric)
- return 0;
-
- return m1->ip_address.s_addr == m2->ip_address.s_addr;
- }
- int pim_assert_build_msg(uint8_t *pim_msg, int buf_size,
- struct interface *ifp,
- struct in_addr group_addr,
- struct in_addr source_addr,
- uint32_t metric_preference,
- uint32_t route_metric,
- uint32_t rpt_bit_flag)
- {
- uint8_t *buf_pastend = pim_msg + buf_size;
- uint8_t *pim_msg_curr;
- int pim_msg_size;
- int remain;
- pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* skip room for pim header */
- /* Encode group */
- remain = buf_pastend - pim_msg_curr;
- pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr,
- remain,
- group_addr);
- if (!pim_msg_curr) {
- char group_str[100];
- pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
- zlog_warn("%s: failure encoding group address %s: space left=%d",
- __PRETTY_FUNCTION__, group_str, remain);
- return -1;
- }
- /* Encode source */
- remain = buf_pastend - pim_msg_curr;
- pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr,
- remain,
- source_addr);
- if (!pim_msg_curr) {
- char source_str[100];
- pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
- zlog_warn("%s: failure encoding source address %s: space left=%d",
- __PRETTY_FUNCTION__, source_str, remain);
- return -2;
- }
- /* Metric preference */
- pim_write_uint32(pim_msg_curr, rpt_bit_flag ?
- metric_preference | 0x80000000 :
- metric_preference);
- pim_msg_curr += 4;
- /* Route metric */
- pim_write_uint32(pim_msg_curr, route_metric);
- pim_msg_curr += 4;
- /*
- Add PIM header
- */
- pim_msg_size = pim_msg_curr - pim_msg;
- pim_msg_build_header(pim_msg, pim_msg_size,
- PIM_MSG_TYPE_ASSERT);
- return pim_msg_size;
- }
- static int pim_assert_do(struct pim_ifchannel *ch,
- struct pim_assert_metric metric)
- {
- struct interface *ifp;
- struct pim_interface *pim_ifp;
- uint8_t pim_msg[1000];
- int pim_msg_size;
- ifp = ch->interface;
- zassert(ifp);
- pim_ifp = ifp->info;
- if (!pim_ifp) {
- zlog_warn("%s: pim not enabled on interface: %s",
- __PRETTY_FUNCTION__, ifp->name);
- return -1;
- }
- pim_msg_size = pim_assert_build_msg(pim_msg, sizeof(pim_msg), ifp,
- ch->group_addr, ch->source_addr,
- metric.metric_preference,
- metric.route_metric,
- metric.rpt_bit_flag);
- if (pim_msg_size < 1) {
- zlog_warn("%s: failure building PIM assert message: msg_size=%d",
- __PRETTY_FUNCTION__, pim_msg_size);
- return -2;
- }
- /*
- RFC 4601: 4.3.1. Sending Hello Messages
-
- Thus, if a router needs to send a Join/Prune or Assert message on
- an interface on which it has not yet sent a Hello message with the
- currently configured IP address, then it MUST immediately send the
- relevant Hello message without waiting for the Hello Timer to
- expire, followed by the Join/Prune or Assert message.
- */
- pim_hello_require(ifp);
- if (PIM_DEBUG_PIM_TRACE) {
- char source_str[100];
- char group_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<grp?>", ch->group_addr, group_str, sizeof(group_str));
- zlog_debug("%s: to %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
- __PRETTY_FUNCTION__,
- ifp->name, source_str, group_str,
- metric.metric_preference,
- metric.route_metric,
- PIM_FORCE_BOOLEAN(metric.rpt_bit_flag));
- }
- if (pim_msg_send(pim_ifp->pim_sock_fd,
- qpim_all_pim_routers_addr,
- pim_msg,
- pim_msg_size,
- ifp->name)) {
- zlog_warn("%s: could not send PIM message on interface %s",
- __PRETTY_FUNCTION__, ifp->name);
- return -3;
- }
- return 0;
- }
- int pim_assert_send(struct pim_ifchannel *ch)
- {
- return pim_assert_do(ch, ch->ifassert_my_metric);
- }
- /*
- RFC 4601: 4.6.4. AssertCancel Messages
- An AssertCancel(S,G) is an infinite metric assert with the RPT bit
- set that names S as the source.
- */
- static int pim_assert_cancel(struct pim_ifchannel *ch)
- {
- struct pim_assert_metric metric;
- metric.rpt_bit_flag = 0;
- metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX;
- metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX;
- metric.ip_address = ch->source_addr;
- return pim_assert_do(ch, metric);
- }
- static int on_assert_timer(struct thread *t)
- {
- struct pim_ifchannel *ch;
- struct interface *ifp;
- zassert(t);
- ch = THREAD_ARG(t);
- zassert(ch);
- ifp = ch->interface;
- zassert(ifp);
- if (PIM_DEBUG_PIM_TRACE) {
- 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("%s: (S,G)=(%s,%s) timer expired on interface %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str, ifp->name);
- }
- ch->t_ifassert_timer = 0;
- switch (ch->ifassert_state) {
- case PIM_IFASSERT_I_AM_WINNER:
- zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
- assert_action_a3(ch);
- break;
- case PIM_IFASSERT_I_AM_LOSER:
- assert_action_a5(ch);
- break;
- default:
- {
- char source_str[100];
- char group_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<grp?>", ch->group_addr, group_str, sizeof(group_str));
- zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s",
- __PRETTY_FUNCTION__,
- source_str, group_str, ch->ifassert_state, ifp->name);
- }
- }
- return 0;
- }
- static void assert_timer_off(struct pim_ifchannel *ch)
- {
- struct interface *ifp;
- zassert(ch);
- ifp = ch->interface;
- zassert(ifp);
- if (PIM_DEBUG_PIM_TRACE) {
- if (ch->t_ifassert_timer) {
- 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("%s: (S,G)=(%s,%s) cancelling timer on interface %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str, ifp->name);
- }
- }
- THREAD_OFF(ch->t_ifassert_timer);
- zassert(!ch->t_ifassert_timer);
- }
- static void pim_assert_timer_set(struct pim_ifchannel *ch,
- int interval)
- {
- struct interface *ifp;
- zassert(ch);
- ifp = ch->interface;
- zassert(ifp);
- assert_timer_off(ch);
- if (PIM_DEBUG_PIM_TRACE) {
- 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("%s: (S,G)=(%s,%s) starting %u sec timer on interface %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str, interval, ifp->name);
- }
- THREAD_TIMER_ON(master, ch->t_ifassert_timer,
- on_assert_timer,
- ch, interval);
- }
- static void pim_assert_timer_reset(struct pim_ifchannel *ch)
- {
- pim_assert_timer_set(ch, PIM_ASSERT_TIME - PIM_ASSERT_OVERRIDE_INTERVAL);
- }
- /*
- RFC 4601: 4.6.1. (S,G) Assert Message State Machine
- (S,G) Assert State machine Actions
- A1: Send Assert(S,G).
- Set Assert Timer to (Assert_Time - Assert_Override_Interval).
- Store self as AssertWinner(S,G,I).
- Store spt_assert_metric(S,I) as AssertWinnerMetric(S,G,I).
- */
- int assert_action_a1(struct pim_ifchannel *ch)
- {
- struct interface *ifp = ch->interface;
- struct pim_interface *pim_ifp;
- zassert(ifp);
- pim_ifp = ifp->info;
- if (!pim_ifp) {
- 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_warn("%s: (S,G)=(%s,%s) multicast not enabled on interface %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str, ifp->name);
- return -1; /* must return since pim_ifp is used below */
- }
- /* Switch to I_AM_WINNER before performing action_a3 below */
- pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_WINNER,
- pim_ifp->primary_address,
- pim_macro_spt_assert_metric(&ch->upstream->rpf,
- pim_ifp->primary_address));
- zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
- if (assert_action_a3(ch)) {
- 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_warn("%s: (S,G)=(%s,%s) assert_action_a3 failure on interface %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str, ifp->name);
- /* warning only */
- }
- zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
- return 0;
- }
- /*
- RFC 4601: 4.6.1. (S,G) Assert Message State Machine
- (S,G) Assert State machine Actions
- A2: Store new assert winner as AssertWinner(S,G,I) and assert
- winner metric as AssertWinnerMetric(S,G,I).
- Set Assert Timer to Assert_Time.
- */
- static void assert_action_a2(struct pim_ifchannel *ch,
- struct pim_assert_metric winner_metric)
- {
- pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_LOSER,
- winner_metric.ip_address,
- winner_metric);
-
- pim_assert_timer_set(ch, PIM_ASSERT_TIME);
- zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER);
- }
- /*
- RFC 4601: 4.6.1. (S,G) Assert Message State Machine
- (S,G) Assert State machine Actions
- A3: Send Assert(S,G).
- Set Assert Timer to (Assert_Time - Assert_Override_Interval).
- */
- static int assert_action_a3(struct pim_ifchannel *ch)
- {
- zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
- pim_assert_timer_reset(ch);
- if (pim_assert_send(ch)) {
- 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_warn("%s: (S,G)=(%s,%s) failure sending assert on interface %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str, ch->interface->name);
- return -1;
- }
- zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
- return 0;
- }
- /*
- RFC 4601: 4.6.1. (S,G) Assert Message State Machine
- (S,G) Assert State machine Actions
- A4: Send AssertCancel(S,G).
- Delete assert info (AssertWinner(S,G,I) and
- AssertWinnerMetric(S,G,I) will then return their default
- values).
- */
- void assert_action_a4(struct pim_ifchannel *ch)
- {
- if (pim_assert_cancel(ch)) {
- 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_warn("%s: failure sending AssertCancel(%s,%s) on interface %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str, ch->interface->name);
- /* log warning only */
- }
- assert_action_a5(ch);
- zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO);
- }
- /*
- RFC 4601: 4.6.1. (S,G) Assert Message State Machine
- (S,G) Assert State machine Actions
- A5: Delete assert info (AssertWinner(S,G,I) and
- AssertWinnerMetric(S,G,I) will then return their default values).
- */
- void assert_action_a5(struct pim_ifchannel *ch)
- {
- reset_ifassert_state(ch);
- zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO);
- }
- /*
- RFC 4601: 4.6.1. (S,G) Assert Message State Machine
- (S,G) Assert State machine Actions
- A6: Store new assert winner as AssertWinner(S,G,I) and assert
- winner metric as AssertWinnerMetric(S,G,I).
- Set Assert Timer to Assert_Time.
- If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true)
- set SPTbit(S,G) to TRUE.
- */
- static void assert_action_a6(struct pim_ifchannel *ch,
- struct pim_assert_metric winner_metric)
- {
- assert_action_a2(ch, winner_metric);
- /*
- If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set
- SPTbit(S,G) to TRUE.
-
- Notice: For PIM SSM, SPTbit(S,G) is already always true.
- */
- zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER);
- }
|