示例#1
0
/*******************************************************************************
 函数名称  : bgp_info_mpath_update
 功能描述  : mpath队列更新
 输入参数  : 
 输出参数  : 
 返 回 值  : 无
--------------------------------------------------------------------------------
 最近一次修改记录 :
 修改作者   :      
 修改目的   :      新添加函数
 修改日期   :       2012-8-15
*******************************************************************************/
void bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best,
               struct bgp_info *old_best, struct list *mp_list, struct bgp_maxpaths_cfg *mpath_cfg)
{
	u16 maxpaths, mpath_count, old_mpath_count;
	struct listnode *mp_node, *mp_next_node;
	struct bgp_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath;
	s32 mpath_changed;
	
	mpath_changed = 0;
	maxpaths = BGP_DEFAULT_MAXPATHS;
	mpath_count = 0;
	cur_mpath = NULL;
	old_mpath_count = 0;
	prev_mpath = new_best;
	mp_node = listhead (mp_list);
	
	if (new_best)
    {
		mpath_count++;
		if (new_best != old_best)
		{
	        bgp_info_mpath_dequeue (new_best);
        }
		maxpaths = (peer_sort (new_best->peer) == BGP_PEER_IBGP) ?
		        mpath_cfg->maxpaths_ibgp : mpath_cfg->maxpaths_ebgp;
    }
    
	if (old_best)
	{
		cur_mpath = bgp_info_mpath_first (old_best);
		old_mpath_count = bgp_info_mpath_count (old_best);
		bgp_info_mpath_count_set (old_best, 0);
		bgp_info_mpath_dequeue (old_best);
	}

	while (mp_node || cur_mpath)
    {
		if (!cur_mpath && (mpath_count >= maxpaths))
		{
	        break;
		}
		mp_next_node = mp_node ? listnextnode (mp_node) : NULL;
		next_mpath = cur_mpath ? bgp_info_mpath_next (cur_mpath) : NULL;
		if (mp_node && (listgetdata (mp_node) == cur_mpath))
        {
			list_delete_node (mp_list, mp_node);
			bgp_info_mpath_dequeue (cur_mpath);
			if ((mpath_count < maxpaths) && bgp_info_nexthop_cmp (prev_mpath, cur_mpath))
	        {
				bgp_info_mpath_enqueue (prev_mpath, cur_mpath);
				prev_mpath = cur_mpath;
				mpath_count++;
	        }
			else
	        {
				mpath_changed = 1;
	        }
			mp_node = mp_next_node;
			cur_mpath = next_mpath;
			continue;
	    }
	    
		if (cur_mpath && (!mp_node || (bgp_info_mpath_cmp (cur_mpath, listgetdata (mp_node)) < 0)))
		{
			bgp_info_mpath_dequeue (cur_mpath);
			mpath_changed = 1;
			cur_mpath = next_mpath;
		}
		else
        {
			new_mpath = listgetdata (mp_node);
			list_delete_node (mp_list, mp_node);
			if ((mpath_count < maxpaths) && (new_mpath != new_best) &&
	              bgp_info_nexthop_cmp (prev_mpath, new_mpath))
	        {
				if (new_mpath == next_mpath)
				{
					next_mpath = bgp_info_mpath_next (new_mpath);
				}	
				bgp_info_mpath_dequeue (new_mpath);

				bgp_info_mpath_enqueue (prev_mpath, new_mpath);
				prev_mpath = new_mpath;
				mpath_changed = 1;
				mpath_count++;
            }
			mp_node = mp_next_node;
	    }
	}
	
	if (new_best)
	{
		bgp_info_mpath_count_set (new_best, mpath_count-1);
		if (mpath_changed || (bgp_info_mpath_count (new_best) != old_mpath_count))
		{
	        SET_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG);
        }
	}
}
示例#2
0
/*******************************************************************************
 函数名称  : bgp_info_mpath_aggregate_update
 功能描述  : mpath聚合路由更新
 输入参数  : 
 输出参数  : 
 返 回 值  : 无
--------------------------------------------------------------------------------
 最近一次修改记录 :
 修改作者   :      
 修改目的   :      新添加函数
 修改日期   :       2012-8-15
*******************************************************************************/
void bgp_info_mpath_aggregate_update (struct bgp_info *new_best, struct bgp_info *old_best)
{
	struct bgp_info *mpinfo;
	struct aspath *aspath;
	struct aspath *asmerge;
	struct attr *new_attr, *old_attr;
	u8 origin, attr_chg;
	struct community *community, *commerge;
	struct ecommunity *ecomm, *ecommerge;
	struct attr_extra *ae;
	struct attr attr = { 0 };
	
	if (old_best && (old_best != new_best) &&
	      (old_attr = bgp_info_mpath_attr (old_best)))
	{
		bgp_attr_unintern (&old_attr);
		bgp_info_mpath_attr_set (old_best, NULL);
	}
	
	if (!new_best)
	{
	    return;
	}
	if (!bgp_info_mpath_count (new_best))
	{
		if ((new_attr = bgp_info_mpath_attr (new_best)))
	    {
			bgp_attr_unintern (&new_attr);
			bgp_info_mpath_attr_set (new_best, NULL);
			SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED);
	    }
		return;
	}

	if (!CHECK_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG) &&
				      (old_best == new_best))
	{
		attr_chg = 0;
		
		if (CHECK_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED))
		{
	        attr_chg = 1;
	    }    
		else
		{
			for (mpinfo = bgp_info_mpath_first (new_best); mpinfo;
			     mpinfo = bgp_info_mpath_next (mpinfo))
			{
				if (CHECK_FLAG (mpinfo->flags, BGP_INFO_ATTR_CHANGED))
				{
					attr_chg = 1;
					break;
				}
			}
		}	
		if (!attr_chg)
	    {
			return;
	    }
	}
	
	bgp_attr_dup (&attr, new_best->attr);
	
	/* aggregate attribute from multipath constituents */
	aspath = aspath_dup (attr.aspath);
	origin = attr.origin;
	community = attr.community ? community_dup (attr.community) : NULL;
	ae = attr.extra;
	ecomm = (ae && ae->ecommunity) ? ecommunity_dup (ae->ecommunity) : NULL;
	
	for (mpinfo = bgp_info_mpath_first (new_best); mpinfo;
		       mpinfo = bgp_info_mpath_next (mpinfo))
	{
		asmerge = aspath_aggregate (aspath, mpinfo->attr->aspath);
		aspath_free (aspath);
		aspath = asmerge;
		
		if (origin < mpinfo->attr->origin)
		{
	        origin = mpinfo->attr->origin;
		}
		if (mpinfo->attr->community)
	    {
			if (community)
	        {
				commerge = community_merge (community, mpinfo->attr->community);
				community = community_uniq_sort (commerge);
				community_free (&commerge);
	        }
			else
			{
				community = community_dup (mpinfo->attr->community);
			}
	    }
	    
		ae = mpinfo->attr->extra;
		if (ae && ae->ecommunity)
	    {
			if (ecomm)
			{
				ecommerge = ecommunity_merge (ecomm, ae->ecommunity);
				ecomm = ecommunity_uniq_sort (ecommerge);
				ecommunity_free (ecommerge);
			}
			else
			{
	            ecomm = ecommunity_dup (ae->ecommunity);
            }
	    }
	}

	attr.aspath = aspath;
	attr.origin = origin;
	if (community)
	{
		attr.community = community;
		attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
	}
	if (ecomm)
	{
		ae = bgp_attr_extra_get (&attr);
		ae->ecommunity = ecomm;
		attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
	}

	/* Zap multipath attr nexthop so we set nexthop to self */
	attr.nexthop.s_addr = 0;
#ifdef HAVE_IPV6
	if (attr.extra)
	{
	    memset (&attr.extra->mp_nexthop_global, 0, sizeof (struct in6_addr));
    }
#endif /* HAVE_IPV6 */

	new_attr = bgp_attr_intern (&attr);
	bgp_attr_extra_free (&attr);
	
	if (new_attr != bgp_info_mpath_attr (new_best))
	{
		if ((old_attr = bgp_info_mpath_attr (new_best)))
		{
			bgp_attr_unintern (&old_attr);
		}
		bgp_info_mpath_attr_set (new_best, new_attr);
		SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED);
	}
	else
	{
	    bgp_attr_unintern (&new_attr);
    }
}
示例#3
0
void
bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, safi_t safi)
{
  int flags;
  u_char distance;
  struct peer *peer;
  struct bgp_info *mpinfo;
  size_t oldsize, newsize;

  if (zclient->sock < 0)
    return;

  if (! zclient->redist[ZEBRA_ROUTE_BGP])
    return;

  flags = 0;
  peer = info->peer;

  if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED)
    {
      SET_FLAG (flags, ZEBRA_FLAG_IBGP);
      SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);
    }

  if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
      || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
    SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);

  /* resize nexthop buffer size if necessary */
  if ((oldsize = stream_get_size (bgp_nexthop_buf)) <
      (sizeof (struct in_addr *) * (bgp_info_mpath_count (info) + 1)))
    {
      newsize = (sizeof (struct in_addr *) * (bgp_info_mpath_count (info) + 1));
      newsize = stream_resize (bgp_nexthop_buf, newsize);
      if (newsize == oldsize)
	{
	  zlog_err ("can't resize nexthop buffer");
	  return;
	}
    }

  stream_reset (bgp_nexthop_buf);

  if (p->family == AF_INET)
    {
      struct zapi_ipv4 api;
      struct in_addr *nexthop;

      api.flags = flags;
      nexthop = &info->attr->nexthop;
      stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
      for (mpinfo = bgp_info_mpath_first (info); mpinfo;
	   mpinfo = bgp_info_mpath_next (mpinfo))
	{
	  nexthop = &mpinfo->attr->nexthop;
	  stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
	}

      api.type = ZEBRA_ROUTE_BGP;
      api.message = 0;
      api.safi = safi;
      SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
      api.nexthop_num = 1 + bgp_info_mpath_count (info);
      api.nexthop = (struct in_addr **)STREAM_DATA (bgp_nexthop_buf);
      api.ifindex_num = 0;
      SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
      api.metric = info->attr->med;

      distance = bgp_distance_apply (p, info, bgp);

      if (distance)
	{
	  SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE);
	  api.distance = distance;
	}

      if (BGP_DEBUG(zebra, ZEBRA))
	{
	  int i;
	  char buf[2][INET_ADDRSTRLEN];
	  zlog_debug("Zebra send: IPv4 route add %s/%d nexthop %s metric %u"
		     " count %d",
		     inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
		     p->prefixlen,
		     inet_ntop(AF_INET, api.nexthop[0], buf[1], sizeof(buf[1])),
		     api.metric, api.nexthop_num);
	  for (i = 1; i < api.nexthop_num; i++)
	    zlog_debug("Zebra send: IPv4 route add [nexthop %d] %s",
		       i, inet_ntop(AF_INET, api.nexthop[i], buf[1],
				    sizeof(buf[1])));
	}

      zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, 
                       (struct prefix_ipv4 *) p, &api);
    }
#ifdef HAVE_IPV6
  /* We have to think about a IPv6 link-local address curse. */
  if (p->family == AF_INET6)
    {
      unsigned int ifindex;
      struct in6_addr *nexthop;
      struct zapi_ipv6 api;

      ifindex = 0;
      nexthop = NULL;
      
      assert (info->attr->extra);
      
      /* Only global address nexthop exists. */
      if (info->attr->extra->mp_nexthop_len == 16)
	nexthop = &info->attr->extra->mp_nexthop_global;
      
      /* If both global and link-local address present. */
      if (info->attr->extra->mp_nexthop_len == 32)
	{
	  /* Workaround for Cisco's nexthop bug.  */
	  if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global)
	      && peer->su_remote->sa.sa_family == AF_INET6)
	    nexthop = &peer->su_remote->sin6.sin6_addr;
	  else
	    nexthop = &info->attr->extra->mp_nexthop_local;

	  if (info->peer->nexthop.ifp)
	    ifindex = info->peer->nexthop.ifp->ifindex;
	}

      if (nexthop == NULL)
	return;

      if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex)
	{
	  if (info->peer->ifname)
	    ifindex = if_nametoindex (info->peer->ifname);
	  else if (info->peer->nexthop.ifp)
	    ifindex = info->peer->nexthop.ifp->ifindex;
	}

      /* Make Zebra API structure. */
      api.flags = flags;
      api.type = ZEBRA_ROUTE_BGP;
      api.message = 0;
      api.safi = safi;
      SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
      api.nexthop_num = 1;
      api.nexthop = &nexthop;
      SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
      api.ifindex_num = 1;
      api.ifindex = &ifindex;
      SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
      api.metric = info->attr->med;

      if (BGP_DEBUG(zebra, ZEBRA))
	{
	  char buf[2][INET6_ADDRSTRLEN];
	  zlog_debug("Zebra send: IPv6 route add %s/%d nexthop %s metric %u",
		     inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
		     p->prefixlen,
		     inet_ntop(AF_INET6, nexthop, buf[1], sizeof(buf[1])),
		     api.metric);
	}

      zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, 
                       (struct prefix_ipv6 *) p, &api);
    }
#endif /* HAVE_IPV6 */
}