Exemplo n.º 1
0
/* 11.2.A4 and 11.2.A5: transition active or passive peer to
 * established state */
void pim_msdp_peer_established(struct pim_msdp_peer *mp)
{
	if (mp->state != PIM_MSDP_ESTABLISHED) {
		++mp->est_flaps;
	}

	mp->state = PIM_MSDP_ESTABLISHED;
	mp->uptime = pim_time_monotonic_sec();

	if (PIM_DEBUG_MSDP_EVENTS) {
		pim_msdp_peer_state_chg_log(mp);
	}

	/* stop retry timer on active peers */
	pim_msdp_peer_cr_timer_setup(mp, false /* start */);

	/* send KA; start KA and hold timers */
	pim_msdp_pkt_ka_tx(mp);
	pim_msdp_peer_ka_timer_setup(mp, true /* start */);
	pim_msdp_peer_hold_timer_setup(mp, true /* start */);

	pim_msdp_pkt_sa_tx_to_one_peer(mp);

	PIM_MSDP_PEER_WRITE_ON(mp);
	PIM_MSDP_PEER_READ_ON(mp);
}
static struct pim_upstream *pim_upstream_new(struct in_addr source_addr,
					     struct in_addr group_addr)
{
  struct pim_upstream *up;

  up = XMALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
  if (!up) {
    zlog_err("%s: PIM XMALLOC(%zu) failure",
	     __PRETTY_FUNCTION__, sizeof(*up));
    return 0;
  }
  
  up->source_addr                = source_addr;
  up->group_addr                 = group_addr;
  up->flags                      = 0;
  up->ref_count                  = 1;
  up->t_join_timer               = 0;
  up->join_state                 = 0;
  up->state_transition           = pim_time_monotonic_sec();
  up->channel_oil                = 0;

  up->rpf.source_nexthop.interface                = 0;
  up->rpf.source_nexthop.mrib_nexthop_addr.s_addr = PIM_NET_INADDR_ANY;
  up->rpf.source_nexthop.mrib_metric_preference   = qpim_infinite_assert_metric.metric_preference;
  up->rpf.source_nexthop.mrib_route_metric        = qpim_infinite_assert_metric.route_metric;
  up->rpf.rpf_addr.s_addr                         = PIM_NET_INADDR_ANY;

  pim_rpf_update(up, 0);

  listnode_add(qpim_upstream_list, up);

  return up;
}
Exemplo n.º 3
0
int pim_sock_add(struct interface *ifp)
{
  struct pim_interface *pim_ifp;
  struct in_addr ifaddr;
  uint32_t old_genid;

  pim_ifp = ifp->info;
  zassert(pim_ifp);

  if (pim_ifp->pim_sock_fd >= 0) {
    zlog_warn("Can't recreate existing PIM socket fd=%d for interface %s",
	      pim_ifp->pim_sock_fd, ifp->name);
    return -1;
  }

  ifaddr = pim_ifp->primary_address;

  pim_ifp->pim_sock_fd = pim_sock_open(ifaddr, ifp->ifindex);
  if (pim_ifp->pim_sock_fd < 0) {
    zlog_warn("Could not open PIM socket on interface %s",
	      ifp->name);
    return -2;
  }

  pim_ifp->t_pim_sock_read   = 0;
  pim_ifp->pim_sock_creation = pim_time_monotonic_sec();

  /*
   * Just ensure that the new generation id
   * actually chooses something different.
   * Actually ran across a case where this
   * happened, pre-switch to random().
   * While this is unlikely to happen now
   * let's make sure it doesn't.
   */
  old_genid = pim_ifp->pim_generation_id;

  while (old_genid == pim_ifp->pim_generation_id)
    pim_ifp->pim_generation_id = random();

  zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d",
	    ifp->name, ifp->ifindex);

  /*
   * Start receiving PIM messages
   */
  pim_sock_read_on(ifp);

  /*
   * Start sending PIM hello's
   */
  pim_hello_restart_triggered(ifp);

  return 0;
}
Exemplo n.º 4
0
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);
  }
}
Exemplo n.º 5
0
static struct igmp_sock *igmp_sock_new(int fd,
				       struct in_addr ifaddr,
				       struct interface *ifp)
{
  struct pim_interface *pim_ifp;
  struct igmp_sock *igmp;

  pim_ifp = ifp->info;

  if (PIM_DEBUG_IGMP_TRACE) {
    zlog_debug("Creating IGMP socket fd=%d for address %s on interface %s",
	       fd, inet_ntoa(ifaddr), ifp->name);
  }

  igmp = XMALLOC(MTYPE_PIM_IGMP_SOCKET, sizeof(*igmp));
  if (!igmp) {
    zlog_warn("%s %s: XMALLOC() failure",
              __FILE__, __PRETTY_FUNCTION__);
    return 0;
  }

  igmp->igmp_group_list = list_new();
  if (!igmp->igmp_group_list) {
    zlog_err("%s %s: failure: igmp_group_list = list_new()",
	     __FILE__, __PRETTY_FUNCTION__);
    return 0;
  }
  igmp->igmp_group_list->del = (void (*)(void *)) igmp_group_free;

  igmp->fd                          = fd;
  igmp->interface                   = ifp;
  igmp->ifaddr                      = ifaddr;
  igmp->t_igmp_read                 = 0;
  igmp->t_igmp_query_timer          = 0;
  igmp->t_other_querier_timer       = 0; /* no other querier present */
  igmp->querier_robustness_variable = pim_ifp->igmp_default_robustness_variable;
  igmp->sock_creation               = pim_time_monotonic_sec();

  /*
    igmp_startup_mode_on() will reset QQI:

    igmp->querier_query_interval = pim_ifp->igmp_default_query_interval;
  */
  igmp_startup_mode_on(igmp);

  igmp_read_on(igmp);
  pim_igmp_general_query_on(igmp);

  return igmp;
}
Exemplo n.º 6
0
static struct ssmpingd_sock *ssmpingd_new(struct in_addr source_addr)
{
  struct ssmpingd_sock *ss;
  int sock_fd;

  if (!qpim_ssmpingd_list) {
    qpim_ssmpingd_list = list_new();
    if (!qpim_ssmpingd_list) {
      zlog_err("%s %s: failure: qpim_ssmpingd_list=list_new()",
	       __FILE__, __PRETTY_FUNCTION__);
      return 0;
    }
    qpim_ssmpingd_list->del = (void (*)(void *)) ssmpingd_free;
  }

  sock_fd = ssmpingd_socket(source_addr, /* port: */ 4321, /* mTTL: */ 64);
  if (sock_fd < 0) {
    char source_str[100];
    pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
    zlog_warn("%s: ssmpingd_socket() failure for source %s",
	      __PRETTY_FUNCTION__, source_str);
    return 0;
  }

  ss = XMALLOC(MTYPE_PIM_SSMPINGD, sizeof(*ss));
  if (!ss) {
    char source_str[100];
    pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
    zlog_err("%s: XMALLOC(%zu) failure for ssmpingd source %s",
	     __PRETTY_FUNCTION__,
	     sizeof(*ss), source_str);
    close(sock_fd);
    return 0;
  }

  ss->sock_fd     = sock_fd;
  ss->t_sock_read = 0;
  ss->source_addr = source_addr;
  ss->creation    = pim_time_monotonic_sec();
  ss->requests    = 0;

  listnode_add(qpim_ssmpingd_list, ss);

  ssmpingd_read_on(ss);

  return ss;
}
Exemplo n.º 7
0
void pim_ifstat_reset(struct interface *ifp)
{
  struct pim_interface *pim_ifp;

  zassert(ifp);

  pim_ifp = ifp->info;
  if (!pim_ifp) {
    return;
  }

  pim_ifp->pim_ifstat_start          = pim_time_monotonic_sec();
  pim_ifp->pim_ifstat_hello_sent     = 0;
  pim_ifp->pim_ifstat_hello_sendfail = 0;
  pim_ifp->pim_ifstat_hello_recv     = 0;
  pim_ifp->pim_ifstat_hello_recvfail = 0;
}
static struct igmp_join *igmp_join_new(struct interface *ifp,
				       struct in_addr group_addr,
				       struct in_addr source_addr)
{
  struct pim_interface *pim_ifp;
  struct igmp_join *ij;
  int join_fd;

  pim_ifp = ifp->info;
  zassert(pim_ifp);

  join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr);
  if (join_fd < 0) {
    char group_str[100];
    char source_str[100];
    pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
    pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
    zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
	      __PRETTY_FUNCTION__,
	      group_str, source_str, ifp->name);
    return 0;
  }

  ij = XMALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
  if (!ij) {
    char group_str[100];
    char source_str[100];
    pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
    pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
    zlog_err("%s: XMALLOC(%zu) failure for IGMP group %s source %s on interface %s",
	     __PRETTY_FUNCTION__,
	     sizeof(*ij), group_str, source_str, ifp->name);
    close(join_fd);
    return 0;
  }

  ij->sock_fd       = join_fd;
  ij->group_addr    = group_addr;
  ij->source_addr   = source_addr;
  ij->sock_creation = pim_time_monotonic_sec();

  listnode_add(pim_ifp->igmp_join_list, ij);

  return ij;
}
Exemplo n.º 9
0
static int on_rpf_cache_refresh(struct thread *t)
{
  zassert(t);
  zassert(qpim_rpf_cache_refresher);

  qpim_rpf_cache_refresher = 0;

  /* update PIM protocol state */
  scan_upstream_rpf_cache();

  /* update kernel multicast forwarding cache (MFC) */
  pim_scan_oil();

  qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
  ++qpim_rpf_cache_refresh_events;

  return 0;
}
static void pim_upstream_switch(struct pim_upstream *up,
				enum pim_upstream_state new_state)
{
  enum pim_upstream_state old_state = up->join_state;

  zassert(old_state != new_state);
  
  up->join_state       = new_state;
  up->state_transition = pim_time_monotonic_sec();

  if (PIM_DEBUG_PIM_EVENTS) {
    char src_str[100];
    char grp_str[100];
    pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
    pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
    zlog_debug("%s: PIM_UPSTREAM_%s: (S,G)=(%s,%s)",
	       __PRETTY_FUNCTION__,
	       ((new_state == PIM_UPSTREAM_JOINED) ? "JOINED" : "NOTJOINED"),
	       src_str, grp_str);
  }

  pim_upstream_update_assert_tracking_desired(up);

  if (new_state == PIM_UPSTREAM_JOINED) {
    forward_on(up);
    send_join(up);
    join_timer_start(up);
  }
  else {
    forward_off(up);
    pim_joinprune_send(up->rpf.source_nexthop.interface,
		       up->rpf.rpf_addr,
		       up->source_addr,
		       up->group_addr,
		       0 /* prune */);
    zassert(up->t_join_timer);
    THREAD_OFF(up->t_join_timer);
  }

}
Exemplo n.º 11
0
/*
  RFC 4601: 4.3.2.  DR Election

  A router's idea of the current DR on an interface can change when a
  PIM Hello message is received, when a neighbor times out, or when a
  router's own DR Priority changes.
 */
int pim_if_dr_election(struct interface *ifp)
{
  struct pim_interface *pim_ifp = ifp->info;
  struct in_addr old_dr_addr;

  ++pim_ifp->pim_dr_election_count;

  old_dr_addr = pim_ifp->pim_dr_addr;

  if (pim_ifp->pim_dr_num_nondrpri_neighbors) {
    dr_election_by_addr(ifp);
  }
  else {
    dr_election_by_pri(ifp);
  }

  /* DR changed ? */
  if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) {

    if (PIM_DEBUG_PIM_EVENTS) {
      char dr_old_str[100];
      char dr_new_str[100];
      pim_inet4_dump("<old_dr?>", old_dr_addr, dr_old_str, sizeof(dr_old_str));
      pim_inet4_dump("<new_dr?>", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str));
      zlog_debug("%s: DR was %s now is %s on interface %s",
		 __PRETTY_FUNCTION__,
		 dr_old_str, dr_new_str, ifp->name);
    }

    pim_ifp->pim_dr_election_last = pim_time_monotonic_sec(); /* timestamp */
    ++pim_ifp->pim_dr_election_changes; 
    pim_if_update_join_desired(pim_ifp);
    pim_if_update_could_assert(ifp);
    pim_if_update_assert_tracking_desired(ifp);
    return 1;
  }

  return 0;
}
Exemplo n.º 12
0
static struct ssmpingd_sock *ssmpingd_new(struct pim_instance *pim,
					  struct in_addr source_addr)
{
	struct ssmpingd_sock *ss;
	int sock_fd;

	if (!pim->ssmpingd_list) {
		pim->ssmpingd_list = list_new();
		pim->ssmpingd_list->del = (void (*)(void *))ssmpingd_free;
	}

	sock_fd =
		ssmpingd_socket(source_addr, /* port: */ 4321, /* mTTL: */ 64);
	if (sock_fd < 0) {
		char source_str[INET_ADDRSTRLEN];
		pim_inet4_dump("<src?>", source_addr, source_str,
			       sizeof(source_str));
		zlog_warn("%s: ssmpingd_socket() failure for source %s",
			  __PRETTY_FUNCTION__, source_str);
		return 0;
	}

	ss = XCALLOC(MTYPE_PIM_SSMPINGD, sizeof(*ss));

	ss->pim = pim;
	ss->sock_fd = sock_fd;
	ss->t_sock_read = NULL;
	ss->source_addr = source_addr;
	ss->creation = pim_time_monotonic_sec();
	ss->requests = 0;

	listnode_add(pim->ssmpingd_list, ss);

	ssmpingd_read_on(ss);

	return ss;
}
Exemplo n.º 13
0
static struct static_route *static_route_new(unsigned int   iif,
                                             unsigned int   oif,
                                             struct in_addr group,
                                             struct in_addr source)
{
  struct static_route * s_route;
  s_route = static_route_alloc();
  if (!s_route) {
     return 0;
  }

  s_route->group             = group;
  s_route->source            = source;
  s_route->iif               = iif;
  s_route->oif_ttls[oif]     = 1;
  s_route->oif_count         = 1;
  s_route->mc.mfcc_origin    = source;
  s_route->mc.mfcc_mcastgrp  = group;
  s_route->mc.mfcc_parent    = iif;
  s_route->mc.mfcc_ttls[oif] = 1;
  s_route->creation[oif] = pim_time_monotonic_sec();

  return s_route;
}
Exemplo n.º 14
0
static struct pim_msdp_sa *pim_msdp_sa_new(struct pim_instance *pim,
					   struct prefix_sg *sg,
					   struct in_addr rp)
{
	struct pim_msdp_sa *sa;

	sa = XCALLOC(MTYPE_PIM_MSDP_SA, sizeof(*sa));

	sa->pim = pim;
	sa->sg = *sg;
	pim_str_sg_set(sg, sa->sg_str);
	sa->rp = rp;
	sa->uptime = pim_time_monotonic_sec();

	/* insert into misc tables for easy access */
	sa = hash_get(pim->msdp.sa_hash, sa, hash_alloc_intern);
	listnode_add_sort(pim->msdp.sa_list, sa);

	if (PIM_DEBUG_MSDP_EVENTS) {
		zlog_debug("MSDP SA %s created", sa->sg_str);
	}

	return sa;
}
Exemplo n.º 15
0
static struct pim_neighbor *pim_neighbor_new(struct interface *ifp,
					     struct in_addr source_addr,
					     pim_hello_options hello_options,
					     uint16_t holdtime,
					     uint16_t propagation_delay,
					     uint16_t override_interval,
					     uint32_t dr_priority,
					     uint32_t generation_id,
					     struct list *addr_list)
{
  struct pim_interface *pim_ifp;
  struct pim_neighbor *neigh;
  char src_str[100];

  zassert(ifp);
  pim_ifp = ifp->info;
  zassert(pim_ifp);

  neigh = XMALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh));
  if (!neigh) {
    zlog_err("%s: PIM XMALLOC(%zu) failure",
	     __PRETTY_FUNCTION__, sizeof(*neigh));
    return 0;
  }

  neigh->creation               = pim_time_monotonic_sec();
  neigh->source_addr            = source_addr;
  neigh->hello_options          = hello_options;
  neigh->propagation_delay_msec = propagation_delay;
  neigh->override_interval_msec = override_interval;
  neigh->dr_priority            = dr_priority;
  neigh->generation_id          = generation_id;
  neigh->prefix_list            = addr_list;
  neigh->t_expire_timer         = 0;
  neigh->interface              = ifp;

  pim_neighbor_timer_reset(neigh, holdtime);

  pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));

  if (PIM_DEBUG_PIM_EVENTS) {
    zlog_debug("%s: creating PIM neighbor %s on interface %s",
	       __PRETTY_FUNCTION__,
	       src_str, ifp->name);
  }

  zlog_info("PIM NEIGHBOR UP: neighbor %s on interface %s",
	    src_str, ifp->name);

  if (neigh->propagation_delay_msec > pim_ifp->pim_neighbors_highest_propagation_delay_msec) {
    pim_ifp->pim_neighbors_highest_propagation_delay_msec = neigh->propagation_delay_msec;
  }
  if (neigh->override_interval_msec > pim_ifp->pim_neighbors_highest_override_interval_msec) {
    pim_ifp->pim_neighbors_highest_override_interval_msec = neigh->override_interval_msec;
  }

  if (!PIM_OPTION_IS_SET(neigh->hello_options,
			 PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
    /* update num. of neighbors without hello option lan_delay */
    ++pim_ifp->pim_number_of_nonlandelay_neighbors; 
  }

  if (!PIM_OPTION_IS_SET(neigh->hello_options,
			 PIM_OPTION_MASK_DR_PRIORITY)) {
    /* update num. of neighbors without hello option dr_pri */
    ++pim_ifp->pim_dr_num_nondrpri_neighbors; 
  }

  return neigh;
}
Exemplo n.º 16
0
int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source)
{
   struct listnode *node = 0;
   struct static_route *s_route = 0;
   struct static_route *original_s_route = 0;
   struct pim_interface *pim_iif = iif ? iif->info : 0;
   struct pim_interface *pim_oif = oif ? oif->info : 0;
   unsigned int iif_index = pim_iif ? pim_iif->mroute_vif_index : 0;
   unsigned int oif_index = pim_oif ? pim_oif->mroute_vif_index : 0;

   if (!iif_index || !oif_index) {
      zlog_warn("%s %s: Unable to add static route: Invalid interface index(iif=%d,oif=%d)",
               __FILE__, __PRETTY_FUNCTION__,
               iif_index,
               oif_index);
      return -2;
   }

#ifdef PIM_ENFORCE_LOOPFREE_MFC
   if (iif_index == oif_index) {
      /* looped MFC entry */
      zlog_warn("%s %s: Unable to add static route: Looped MFC entry(iif=%d,oif=%d)",
               __FILE__, __PRETTY_FUNCTION__,
               iif_index,
               oif_index);
      return -4;
   }
#endif

   for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) {
      if (s_route->group.s_addr == group.s_addr &&
          s_route->source.s_addr == source.s_addr) {
         if (s_route->iif == iif_index &&
             s_route->oif_ttls[oif_index]) {
            char gifaddr_str[100];
            char sifaddr_str[100];
            pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
            pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
            zlog_warn("%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%s,source=%s)",
                     __FILE__, __PRETTY_FUNCTION__,
                     iif_index,
                     oif_index,
                     gifaddr_str,
                     sifaddr_str);
            return -3;
         }

         /* Ok, from here on out we will be making changes to the s_route structure, but if
          * for some reason we fail to commit these changes to the kernel, we want to be able
          * restore the state of the list. So copy the node data and if need be, we can copy
          * back if it fails.
          */
         original_s_route = static_route_alloc();
         if (!original_s_route) {
            return -5;
         }
         memcpy(original_s_route, s_route, sizeof(struct static_route));

         /* Route exists and has the same input interface, but adding a new output interface */
         if (s_route->iif == iif_index) {
            s_route->oif_ttls[oif_index] = 1;
            s_route->mc.mfcc_ttls[oif_index] = 1;
            s_route->creation[oif_index] = pim_time_monotonic_sec();
            ++s_route->oif_count;
         } else {
            /* input interface changed */
            s_route->iif = iif_index;
            s_route->mc.mfcc_parent = iif_index;

#ifdef PIM_ENFORCE_LOOPFREE_MFC
            /* check to make sure the new input was not an old output */
            if (s_route->oif_ttls[iif_index]) {
               s_route->oif_ttls[iif_index] = 0;
               s_route->creation[iif_index] = 0;
               s_route->mc.mfcc_ttls[iif_index] = 0;
               --s_route->oif_count;
            }
#endif

            /* now add the new output, if it is new */
            if (!s_route->oif_ttls[oif_index]) {
               s_route->oif_ttls[oif_index] = 1;
               s_route->creation[oif_index] = pim_time_monotonic_sec();
               s_route->mc.mfcc_ttls[oif_index] = 1;
               ++s_route->oif_count;
            }
         }

         break;
      }
   }

   /* If node is null then we reached the end of the list without finding a match */
   if (!node) {
      s_route = static_route_new(iif_index, oif_index, group, source);
      listnode_add(qpim_static_route_list, s_route);
   }

   if (pim_mroute_add(&(s_route->mc)))
   {
      char gifaddr_str[100];
      char sifaddr_str[100];
      pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
      pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
      zlog_warn("%s %s: Unable to add static route(iif=%d,oif=%d,group=%s,source=%s)",
               __FILE__, __PRETTY_FUNCTION__,
               iif_index,
               oif_index,
               gifaddr_str,
               sifaddr_str);

      /* Need to put s_route back to the way it was */
      if (original_s_route) {
         memcpy(s_route, original_s_route, sizeof(struct static_route));
      } else {
         /* we never stored off a copy, so it must have been a fresh new route */
         listnode_delete(qpim_static_route_list, s_route);
         pim_static_route_free(s_route);
      }

      return -1;
   }

   /* Make sure we free the memory for the route copy if used */
   if (original_s_route) {
      pim_static_route_free(original_s_route);
   }

   if (PIM_DEBUG_STATIC) {
     char gifaddr_str[100];
     char sifaddr_str[100];
     pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
     pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
     zlog_debug("%s: Static route added(iif=%d,oif=%d,group=%s,source=%s)",
           __PRETTY_FUNCTION__,
           iif_index,
           oif_index,
           gifaddr_str,
           sifaddr_str);
   }

   return 0;
}
Exemplo n.º 17
0
void pim_scan_oil()
{
  struct listnode    *node;
  struct listnode    *nextnode;
  struct channel_oil *c_oil;

  qpim_scan_oil_last = pim_time_monotonic_sec();
  ++qpim_scan_oil_events;

  for (ALL_LIST_ELEMENTS(qpim_channel_oil_list, node, nextnode, c_oil)) {
    int old_vif_index;
    int input_iface_vif_index = fib_lookup_if_vif_index(c_oil->oil.mfcc_origin);
    if (input_iface_vif_index < 1) {
      char source_str[100];
      char group_str[100];
      pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
      pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
      zlog_warn("%s %s: could not find input interface for (S,G)=(%s,%s)",
		__FILE__, __PRETTY_FUNCTION__,
		source_str, group_str);
      continue;
    }

    if (input_iface_vif_index == c_oil->oil.mfcc_parent) {
      /* RPF unchanged */
      continue;
    }

    if (PIM_DEBUG_ZEBRA) {
      struct interface *old_iif = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent);
      struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
      char source_str[100];
      char group_str[100];
      pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
      pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
      zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
		 __FILE__, __PRETTY_FUNCTION__,
		 source_str, group_str,
		 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
		 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
    }

    /* new iif loops to existing oif ? */
    if (c_oil->oil.mfcc_ttls[input_iface_vif_index]) {
      struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);

      if (PIM_DEBUG_ZEBRA) {
	char source_str[100];
	char group_str[100];
	pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
	pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
	zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
		   __FILE__, __PRETTY_FUNCTION__,
		   source_str, group_str,
		   new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
      }

      del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY);
    }

    /* update iif vif_index */
    old_vif_index = c_oil->oil.mfcc_parent;
    c_oil->oil.mfcc_parent = input_iface_vif_index;

    /* update kernel multicast forwarding cache (MFC) */
    if (pim_mroute_add(&c_oil->oil)) {
      /* just log warning */
      struct interface *old_iif = pim_if_find_by_vif_index(old_vif_index);
      struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
      char source_str[100];
      char group_str[100]; 
      pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
      pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
      zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
		 __FILE__, __PRETTY_FUNCTION__,
		 source_str, group_str,
		 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
		 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
      continue;
    }

  } /* for (qpim_channel_oil_list) */
}
Exemplo n.º 18
0
struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp,
					  struct in_addr group_addr,
					  const char *ifname)
{
  struct igmp_group *group;

  group = find_group_by_addr(igmp, group_addr);
  if (group) {
    return group;
  }

  /*
    Non-existant group is created as INCLUDE {empty}:

    RFC 3376 - 5.1. Action on Change of Interface State

    If no interface state existed for that multicast address before
    the change (i.e., the change consisted of creating a new
    per-interface record), or if no state exists after the change
    (i.e., the change consisted of deleting a per-interface record),
    then the "non-existent" state is considered to have a filter mode
    of INCLUDE and an empty source list.
  */

  group = XMALLOC(MTYPE_PIM_IGMP_GROUP, sizeof(*group));
  if (!group) {
    zlog_warn("%s %s: XMALLOC() failure",
	      __FILE__, __PRETTY_FUNCTION__);
    return 0; /* error, not found, could not create */
  }

  group->group_source_list = list_new();
  if (!group->group_source_list) {
    zlog_warn("%s %s: list_new() failure",
	      __FILE__, __PRETTY_FUNCTION__);
    XFREE(MTYPE_PIM_IGMP_GROUP, group); /* discard group */
    return 0; /* error, not found, could not initialize */
  }
  group->group_source_list->del = (void (*)(void *)) igmp_source_free;

  group->t_group_timer                         = 0;
  group->t_group_query_retransmit_timer        = 0;
  group->group_specific_query_retransmit_count = 0;
  group->group_addr                            = group_addr;
  group->group_igmp_sock                       = igmp;
  group->last_igmp_v1_report_dsec              = -1;
  group->last_igmp_v2_report_dsec              = -1;
  group->group_creation                        = pim_time_monotonic_sec();

  /* initialize new group as INCLUDE {empty} */
  group->group_filtermode_isexcl = 0; /* 0=INCLUDE, 1=EXCLUDE */

  listnode_add(igmp->igmp_group_list, group);

  if (PIM_DEBUG_IGMP_TRACE) {
    char group_str[100];
    pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
    zlog_debug("Creating new IGMP group %s on socket %d interface %s",
	       group_str, group->group_igmp_sock->fd, ifname);
  }

  /*
    RFC 3376: 6.2.2. Definition of Group Timers

    The group timer is only used when a group is in EXCLUDE mode and
    it represents the time for the *filter-mode* of the group to
    expire and switch to INCLUDE mode.
  */
  zassert(!group->group_filtermode_isexcl); /* INCLUDE mode */
  zassert(!group->t_group_timer); /* group timer == 0 */

  /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
  igmp_anysource_forward_stop(group);

  return group;
}
Exemplo n.º 19
0
static int add_oif(struct channel_oil *channel_oil,
		   struct interface *oif,
		   uint32_t proto_mask)
{
  struct pim_interface *pim_ifp;
  int old_ttl;

  zassert(channel_oil);

  pim_ifp = oif->info;

  if (PIM_DEBUG_MROUTE) {
    char group_str[100]; 
    char source_str[100];
    pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
    pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
    zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
	       __FILE__, __PRETTY_FUNCTION__,
	       source_str, group_str,
	       proto_mask, oif->name, pim_ifp->mroute_vif_index);
  }

  if (pim_ifp->mroute_vif_index < 1) {
    zlog_warn("%s %s: interface %s vif_index=%d < 1",
	      __FILE__, __PRETTY_FUNCTION__,
	      oif->name, pim_ifp->mroute_vif_index);
    return -1;
  }

#ifdef PIM_ENFORCE_LOOPFREE_MFC
  /*
    Prevent creating MFC entry with OIF=IIF.

    This is a protection against implementation mistakes.

    PIM protocol implicitely ensures loopfree multicast topology.

    IGMP must be protected against adding looped MFC entries created
    by both source and receiver attached to the same interface. See
    TODO T22.
  */
  if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
    char group_str[100]; 
    char source_str[100];
    pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
    pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
    zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
	      __FILE__, __PRETTY_FUNCTION__,
	      proto_mask, oif->name, pim_ifp->mroute_vif_index,
	      source_str, group_str);
    return -2;
  }
#endif

  zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
  zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);

  /* Prevent single protocol from subscribing same interface to
     channel (S,G) multiple times */
  if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
    char group_str[100]; 
    char source_str[100];
    pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
    pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
    zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
	      __FILE__, __PRETTY_FUNCTION__,
	      proto_mask, oif->name, pim_ifp->mroute_vif_index,
	      channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
	      source_str, group_str);
    return -3;
  }

  /* Allow other protocol to request subscription of same interface to
     channel (S,G) multiple times, by silently ignoring further
     requests */
  if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {

    /* Check the OIF really exists before returning, and only log
       warning otherwise */
    if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
      char group_str[100]; 
      char source_str[100];
      pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
      pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
      zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
		__FILE__, __PRETTY_FUNCTION__,
		proto_mask, oif->name, pim_ifp->mroute_vif_index,
		channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
		source_str, group_str);
    }

    return 0;
  }

  old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];

  if (old_ttl > 0) {
    char group_str[100]; 
    char source_str[100];
    pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
    pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
    zlog_warn("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
	      __FILE__, __PRETTY_FUNCTION__,
	      oif->name, pim_ifp->mroute_vif_index,
	      source_str, group_str);
    return -4;
  }

  channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;

  if (pim_mroute_add(&channel_oil->oil)) {
    char group_str[100]; 
    char source_str[100];
    pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
    pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
    zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
	      __FILE__, __PRETTY_FUNCTION__,
	      oif->name, pim_ifp->mroute_vif_index,
	      source_str, group_str);

    channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
    return -5;
  }

  channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec();
  ++channel_oil->oil_size;
  channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;

  if (PIM_DEBUG_MROUTE) {
    char group_str[100]; 
    char source_str[100];
    pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
    pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
    zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
	       __FILE__, __PRETTY_FUNCTION__,
	       source_str, group_str,
	       proto_mask, oif->name, pim_ifp->mroute_vif_index);
  }

  return 0;
}