예제 #1
0
/* `match ipv6 address prefix-list PREFIX_LIST' */
static route_map_result_t
route_match_ipv6_address_prefix_list(void *rule, struct prefix *prefix,
                                    route_map_object_t type, void *object)
{
    struct prefix_list *plist;
    if(type == RMAP_ISIS)
    {
        plist = prefix_list_lookup(AFI_IP6, (s8 *) rule);
        if (plist == NULL)
        {
            return RMAP_NOMATCH;
        }

        if( FILTER_DENY == prefix_list_apply(plist, prefix) )
        {
            return RMAP_NOMATCH;
        }
        else
        {
            return RMAP_MATCH;
        }
    }

    return RMAP_NOMATCH;
}
예제 #2
0
파일: ospf_abr.c 프로젝트: AllardJ/Tomato
int
ospf_abr_plist_out_check (struct ospf_area *area, struct ospf_route *or,
			  struct prefix *p)
{
  if (PREFIX_NAME_OUT (area))
    {
      if (PREFIX_LIST_OUT (area) == NULL)
	PREFIX_LIST_OUT (area) = prefix_list_lookup (AFI_IP,
						     PREFIX_NAME_OUT (area));
      if (PREFIX_LIST_OUT (area))
	if (prefix_list_apply (PREFIX_LIST_OUT (area), p) != PREFIX_PERMIT)
	  return 0;
    }
  return 1;
}
예제 #3
0
static route_map_result_t
route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
				   route_map_object_t type, void *object)
{
	struct prefix_list *plist;

	if (type != RMAP_ISIS)
		return RMAP_NOMATCH;

	plist = prefix_list_lookup(AFI_IP, (char *)rule);
	if (prefix_list_apply(plist, prefix) != PREFIX_DENY)
		return RMAP_MATCH;

	return RMAP_NOMATCH;
}
예제 #4
0
route_map_result_t
route_match_ip_address_prefix_list (void *rule, struct prefix *prefix, 
				    route_map_object_t type, void *object)
{
  struct prefix_list *plist;

  if (type == RMAP_RIP)
    {
      plist = prefix_list_lookup (AFI_IP, (char *) rule);
      if (plist == NULL)
	return RMAP_NOMATCH;
    
      return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
	      RMAP_NOMATCH : RMAP_MATCH);
    }
  return RMAP_NOMATCH;
}
예제 #5
0
static route_map_result_t
route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix,
                                    route_map_object_t type, void *object)
{
  struct prefix_list *plist;
  struct external_info *ei = object;
  struct prefix_ipv4 p;

  if (type == RMAP_OSPF)
    {
      p.family = AF_INET;
      p.prefix = ei->nexthop;
      p.prefixlen = IPV4_MAX_BITLEN;

      plist = prefix_list_lookup (AFI_IP, (char *) rule);
      if (plist == NULL)
        return RMAP_NOMATCH;

      return (prefix_list_apply (plist, &p) == PREFIX_DENY ?
              RMAP_NOMATCH : RMAP_MATCH);
    }
  return RMAP_NOMATCH;
}
예제 #6
0
static route_map_result_t
route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix,
                                    route_map_object_t type, void *object)
{
  struct prefix_list *plist;
  struct rip_info *rinfo;
  struct prefix_ipv4 p;

  if (type == RMAP_RIP)
    {
      rinfo = object;
      p.family = AF_INET;
      p.prefix = (rinfo->nexthop.s_addr) ? rinfo->nexthop : rinfo->from;
      p.prefixlen = IPV4_MAX_BITLEN;

      plist = prefix_list_lookup (AFI_IP, (char *) rule);
      if (plist == NULL)
        return RMAP_NOMATCH;

      return (prefix_list_apply (plist, &p) == PREFIX_DENY ?
              RMAP_NOMATCH : RMAP_MATCH);
    }
  return RMAP_NOMATCH;
}
예제 #7
0
/**
 * @fn eigrp_update_send_GR_part
 *
 * @param[in]		nbr		contains neighbor who would receive Graceful restart
 *
 * @return void
 *
 * @par
 * Function used for sending Graceful restart Update packet
 * and if there are multiple chunks, send only one of them.
 * It is called from thread. Do not call it directly.
 *
 * Uses nbr_gr_packet_type from neighbor.
 */
static void
eigrp_update_send_GR_part(struct eigrp_neighbor *nbr)
{
	struct eigrp_packet *ep;
	u_int16_t length = EIGRP_HEADER_LEN;
	struct listnode *node, *nnode;
	struct eigrp_prefix_entry *pe;
	struct prefix_ipv4 *dest_addr;
	struct eigrp *e;
	struct access_list *alist, *alist_i;
	struct prefix_list *plist, *plist_i;
	struct list *prefixes;
	u_int32_t flags;
	unsigned int send_prefixes;
	struct TLV_IPv4_Internal_type *tlv_max;

	/* get prefixes to send to neighbor */
	prefixes = nbr->nbr_gr_prefixes_send;

	send_prefixes = 0;
	length = EIGRP_HEADER_LEN;

	/* if there already were last packet chunk, we won't continue */
	if(nbr->nbr_gr_packet_type == EIGRP_PACKET_PART_LAST)
		return;

	/* if this is first packet chunk, we need to decide,
	 * if there will be one or more chunks */
	if(nbr->nbr_gr_packet_type == EIGRP_PACKET_PART_FIRST)
	{
		if(prefixes->count <= EIGRP_TLV_MAX_IPv4)
		{
			/* there will be only one chunk */
			flags = EIGRP_INIT_FLAG + EIGRP_RS_FLAG + EIGRP_EOT_FLAG;
			nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_LAST;
		}
		else
		{
			/* there will be more chunks */
			flags = EIGRP_INIT_FLAG + EIGRP_RS_FLAG;
			nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_NA;
		}
	}
	else
	{
		/* this is not first chunk, and we need to decide,
		 * if there will be more chunks */
		if(prefixes->count <= EIGRP_TLV_MAX_IPv4)
		{
			/* this is last chunk */
			flags = EIGRP_EOT_FLAG;
			nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_LAST;
		}
		else
		{
			/* there will be more chunks */
			flags = 0;
			nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_NA;
		}
	}

	ep = eigrp_packet_new(nbr->ei->ifp->mtu);

	/* Prepare EIGRP Graceful restart UPDATE header */
	eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s,
			flags,
			nbr->ei->eigrp->sequence_number,
			nbr->recv_sequence_number);

	// encode Authentication TLV, if needed
	if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
	{
		length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
	}

	for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode, pe))
	{

		/*
		* Filtering
		*/
		dest_addr = pe->destination_ipv4;
		/* get list from eigrp process */
		e = eigrp_lookup();
		/* Get access-lists and prefix-lists from process and interface */
		alist = e->list[EIGRP_FILTER_OUT];
		plist = e->prefix[EIGRP_FILTER_OUT];
		alist_i = nbr->ei->list[EIGRP_FILTER_OUT];
		plist_i = nbr->ei->prefix[EIGRP_FILTER_OUT];


		/* Check if any list fits */
		if ((alist && access_list_apply (alist,
				 (struct prefix *) dest_addr) == FILTER_DENY)||
			  (plist && prefix_list_apply (plist,
						(struct prefix *) dest_addr) == FILTER_DENY)||
			  (alist_i && access_list_apply (alist_i,
						(struct prefix *) dest_addr) == FILTER_DENY)||
			  (plist_i && prefix_list_apply (plist_i,
						(struct prefix *) dest_addr) == FILTER_DENY))
		{
			/* do not send filtered route */
			zlog_info("Filtered prefix %s won't be sent out.",
					inet_ntoa(dest_addr->prefix));
		}
		else
		{
			/* sending route which wasn't filtered */
			length += eigrp_add_internalTLV_to_stream(ep->s, pe);
			send_prefixes++;
		}



		alist = e->list[EIGRP_FILTER_IN];
		plist = e->prefix[EIGRP_FILTER_IN];
		alist_i = nbr->ei->list[EIGRP_FILTER_IN];
		plist_i = nbr->ei->prefix[EIGRP_FILTER_IN];


		/* Check if any list fits */
		if ((alist && access_list_apply (alist,
				 (struct prefix *) dest_addr) == FILTER_DENY)||
			  (plist && prefix_list_apply (plist,
						(struct prefix *) dest_addr) == FILTER_DENY)||
			  (alist_i && access_list_apply (alist_i,
						(struct prefix *) dest_addr) == FILTER_DENY)||
			  (plist_i && prefix_list_apply (plist_i,
						(struct prefix *) dest_addr) == FILTER_DENY))
		{
			/* do not send filtered route */
			zlog_info("Filtered prefix %s will be removed.",
					inet_ntoa(dest_addr->prefix));

			tlv_max = eigrp_IPv4_InternalTLV_new();
			tlv_max->type = EIGRP_TLV_IPv4_INT;
			tlv_max->length = 28U;
			tlv_max->metric = pe->reported_metric;
			/* set delay to MAX */
			tlv_max->metric.delay = EIGRP_MAX_METRIC;
			tlv_max->destination = pe->destination_ipv4->prefix;
			tlv_max->prefix_length = pe->destination_ipv4->prefixlen;


			/* prepare message for FSM */
			struct eigrp_fsm_action_message *fsm_msg;
			fsm_msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
			  sizeof(struct eigrp_fsm_action_message));

			struct eigrp_neighbor_entry *entry =
			  eigrp_prefix_entry_lookup(pe->entries, nbr);

			fsm_msg->packet_type = EIGRP_OPC_UPDATE;
			fsm_msg->eigrp = e;
			fsm_msg->data_type = EIGRP_TLV_IPv4_INT;
			fsm_msg->adv_router = nbr;
			fsm_msg->data.ipv4_int_type = tlv_max;
			fsm_msg->entry = entry;
			fsm_msg->prefix = pe;

			/* send message to FSM */
			int event = eigrp_get_fsm_event(fsm_msg);
			eigrp_fsm_event(fsm_msg, event);

			/* free memory used by TLV */
			eigrp_IPv4_InternalTLV_free (tlv_max);
		}
		/*
		* End of filtering
		*/
		
		/* NULL the pointer */
		dest_addr = NULL;

		/* delete processed prefix from list */
		listnode_delete(prefixes, pe);

		/* if there are enough prefixes, send packet */
		if(send_prefixes >= EIGRP_TLV_MAX_IPv4)
			break;
	}

	/* compute Auth digest */
	if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
	{
		eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
	}

	/* EIGRP Checksum */
	eigrp_packet_checksum(nbr->ei, ep->s, length);

	ep->length = length;
	ep->dst.s_addr = nbr->src.s_addr;

	/*This ack number we await from neighbor*/
	ep->sequence_number = nbr->ei->eigrp->sequence_number;

	if (IS_DEBUG_EIGRP_PACKET(0, RECV))
		zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]",
			   ep->length, ep->sequence_number, inet_ntoa(ep->dst));


	/*Put packet to retransmission queue*/
	eigrp_fifo_push_head(nbr->retrans_queue, ep);

	if (nbr->retrans_queue->count == 1)
	{
		eigrp_send_packet_reliably(nbr);
	}
}
예제 #8
0
void
eigrp_update_send (struct eigrp_interface *ei)
{
  struct eigrp_packet *ep;
  struct listnode *node, *nnode, *nnode2;
  struct eigrp_neighbor *nbr;
  struct eigrp_prefix_entry *pe;
  u_char has_tlv;
  struct access_list *alist;
  struct prefix_list *plist;
  struct access_list *alist_i;
  struct prefix_list *plist_i;
  struct eigrp *e;
  struct prefix_ipv4 *dest_addr;

  u_int16_t length = EIGRP_HEADER_LEN;

  ep = eigrp_packet_new(ei->ifp->mtu);

  /* Prepare EIGRP INIT UPDATE header */
  eigrp_packet_header_init(EIGRP_OPC_UPDATE, ei, ep->s, 0,
                           ei->eigrp->sequence_number, 0);

  // encode Authentication TLV, if needed
  if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
    {
      length += eigrp_add_authTLV_MD5_to_stream(ep->s,ei);
    }

  has_tlv = 0;
  for (ALL_LIST_ELEMENTS(ei->eigrp->topology_changes_internalIPV4, node, nnode, pe))
    {
      if(pe->req_action & EIGRP_FSM_NEED_UPDATE)
        {

    	  /* Get destination address from prefix */
    	  dest_addr = pe->destination_ipv4;

    	  /*
		   * Filtering
		   */
    	  //TODO: Work in progress
		  /* get list from eigrp process */
		  e = eigrp_lookup();
		  /* Get access-lists and prefix-lists from process and interface */
		  alist = e->list[EIGRP_FILTER_OUT];
		  plist = e->prefix[EIGRP_FILTER_OUT];
		  alist_i = ei->list[EIGRP_FILTER_OUT];
		  plist_i = ei->prefix[EIGRP_FILTER_OUT];

		  /* Check if any list fits */
		  if ((alist && access_list_apply (alist,
					 (struct prefix *) dest_addr) == FILTER_DENY)||
				  (plist && prefix_list_apply (plist,
							 (struct prefix *) dest_addr) == FILTER_DENY)||
				  (alist_i && access_list_apply (alist_i,
							(struct prefix *) dest_addr) == FILTER_DENY)||
				  (plist_i && prefix_list_apply (plist_i,
							(struct prefix *) dest_addr) == FILTER_DENY))
		  {
			  zlog_info("PROC OUT: Skipping");
			  //pe->reported_metric.delay = EIGRP_MAX_METRIC;
			  zlog_info("PROC OUT Prefix: %s", inet_ntoa(dest_addr->prefix));
			  continue;
		  } else {
			  zlog_info("PROC OUT: NENastavujem metriku ");
			  length += eigrp_add_internalTLV_to_stream(ep->s, pe);
			  has_tlv = 1;
		  }
		  /*
		   * End of filtering
		   */

		  /* NULL the pointer */
		  dest_addr = NULL;

        }
    }

  if(!has_tlv)
    {
      eigrp_packet_free(ep);
      return;
    }

  if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
    {
      eigrp_make_md5_digest(ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
    }

  /* EIGRP Checksum */
  eigrp_packet_checksum(ei, ep->s, length);
  ep->length = length;

  ep->dst.s_addr = htonl(EIGRP_MULTICAST_ADDRESS);

  /*This ack number we await from neighbor*/
  ep->sequence_number = ei->eigrp->sequence_number;

  if (IS_DEBUG_EIGRP_PACKET(0, RECV))
    zlog_debug("Enqueuing Update length[%u] Seq [%u]",
               length, ep->sequence_number);

  for (ALL_LIST_ELEMENTS(ei->nbrs, node, nnode, nbr))
    {
      if (nbr->state == EIGRP_NEIGHBOR_UP)
        {
          /*Put packet to retransmission queue*/
          eigrp_fifo_push_head(nbr->retrans_queue, ep);

          if (nbr->retrans_queue->count == 1)
            {
              eigrp_send_packet_reliably(nbr);
            }
        }
    }
}
예제 #9
0
void
eigrp_update_send_EOT (struct eigrp_neighbor *nbr)
{
  struct eigrp_packet *ep;
//  struct eigrp_packet *ep_multicast;
  u_int16_t length = EIGRP_HEADER_LEN;
  struct eigrp_neighbor_entry *te;
  struct eigrp_prefix_entry *pe;
  struct listnode *node, *node2, *nnode, *nnode2;
  struct access_list *alist;
  struct prefix_list *plist;
  struct access_list *alist_i;
  struct prefix_list *plist_i;
  struct eigrp *e;
  struct prefix_ipv4 *dest_addr;

  ep = eigrp_packet_new(nbr->ei->ifp->mtu);

  /* Prepare EIGRP EOT UPDATE header */
  eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_EOT_FLAG,
                           nbr->ei->eigrp->sequence_number,
                           nbr->recv_sequence_number);

  // encode Authentication TLV, if needed
  if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
    {
      length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
    }

  for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode, pe))
    {
      for (ALL_LIST_ELEMENTS(pe->entries, node2, nnode2, te))
        {
          if ((te->ei == nbr->ei)
              && (te->prefix->nt == EIGRP_TOPOLOGY_TYPE_REMOTE))
            continue;


          /* Get destination address from prefix */
		  dest_addr = pe->destination_ipv4;

		  /*
		   * Filtering
		   */
		  //TODO: Work in progress
		  /* get list from eigrp process */
		  e = eigrp_lookup();
		  /* Get access-lists and prefix-lists from process and interface */
		  alist = e->list[EIGRP_FILTER_OUT];
		  plist = e->prefix[EIGRP_FILTER_OUT];
		  alist_i = nbr->ei->list[EIGRP_FILTER_OUT];
		  plist_i = nbr->ei->prefix[EIGRP_FILTER_OUT];

		  /* Check if any list fits */
		  if ((alist && access_list_apply (alist,
					 (struct prefix *) dest_addr) == FILTER_DENY)||
				  (plist && prefix_list_apply (plist,
							(struct prefix *) dest_addr) == FILTER_DENY)||
				  (alist_i && access_list_apply (alist_i,
							(struct prefix *) dest_addr) == FILTER_DENY)||
				  (plist_i && prefix_list_apply (plist_i,
							(struct prefix *) dest_addr) == FILTER_DENY))
		  {
			  zlog_info("PROC OUT EOT: Skipping");
			  //pe->reported_metric.delay = EIGRP_MAX_METRIC;
			  zlog_info("PROC OUT EOT Prefix: %s", inet_ntoa(dest_addr->prefix));
			  continue;
		  } else {
			  zlog_info("PROC OUT EOT: NENastavujem metriku ");
			  length += eigrp_add_internalTLV_to_stream(ep->s, pe);
		  }
		  /*
		   * End of filtering
		   */

		  /* NULL the pointer */
		  dest_addr = NULL;

        }
    }

  if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
    {
      eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
    }

  /* EIGRP Checksum */
  eigrp_packet_checksum(nbr->ei, ep->s, length);

  ep->length = length;
  ep->dst.s_addr = nbr->src.s_addr;

  /*This ack number we await from neighbor*/
  ep->sequence_number = nbr->ei->eigrp->sequence_number;

  if (IS_DEBUG_EIGRP_PACKET(0, RECV))
    zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]",
               ep->length, ep->sequence_number, inet_ntoa(ep->dst));

  /*Put packet to retransmission queue*/
  eigrp_fifo_push_head(nbr->retrans_queue, ep);

  if (nbr->retrans_queue->count == 1)
    {
      eigrp_send_packet_reliably(nbr);
    }

}
예제 #10
0
/*
 * EIGRP UPDATE read function
 */
void
eigrp_update_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph,
                      struct stream * s, struct eigrp_interface *ei, int size)
{
  struct eigrp_neighbor *nbr;
  struct TLV_IPv4_Internal_type *tlv;
  struct eigrp_prefix_entry *pe;
  struct eigrp_neighbor_entry *ne;
  u_int32_t flags;
  u_int16_t type;
  uint16_t  length;
  u_char same;
  struct access_list *alist;
  struct prefix_list *plist;
  struct eigrp *e;
  u_char graceful_restart;
  u_char graceful_restart_final;
  struct list *nbr_prefixes;
  int ret;

  /* increment statistics. */
  ei->update_in++;

  /* get neighbor struct */
  nbr = eigrp_nbr_get(ei, eigrph, iph);

  /* neighbor must be valid, eigrp_nbr_get creates if none existed */
  assert(nbr);

  flags = ntohl(eigrph->flags);

  if (flags & EIGRP_CR_FLAG)
    {
      return;
    }

  same = 0;
  graceful_restart = 0;
  graceful_restart_final = 0;
  if((nbr->recv_sequence_number) == (ntohl(eigrph->sequence)))
      same = 1;

  nbr->recv_sequence_number = ntohl(eigrph->sequence);
  if (IS_DEBUG_EIGRP_PACKET(0, RECV))
    zlog_debug("Processing Update size[%u] int(%s) nbr(%s) seq [%u] flags [%0x]",
               size, ifindex2ifname(nbr->ei->ifp->ifindex),
               inet_ntoa(nbr->src),
               nbr->recv_sequence_number, flags);


    if((flags == (EIGRP_INIT_FLAG+EIGRP_RS_FLAG+EIGRP_EOT_FLAG)) && (!same))
    {
    	/* Graceful restart Update received with all routes */

		zlog_info("Neighbor %s (%s) is resync: peer graceful-restart",
				  inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));

		/* get all prefixes from neighbor from topology table */
    	nbr_prefixes = eigrp_neighbor_prefixes_lookup(eigrp, nbr);
    	graceful_restart = 1;
    	graceful_restart_final = 1;
    }
    else if((flags == (EIGRP_INIT_FLAG+EIGRP_RS_FLAG)) && (!same))
    {
    	/* Graceful restart Update received, routes also in next packet */

		zlog_info("Neighbor %s (%s) is resync: peer graceful-restart",
				  inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));

		/* get all prefixes from neighbor from topology table */
    	nbr_prefixes = eigrp_neighbor_prefixes_lookup(eigrp, nbr);
    	/* save prefixes to neighbor for later use */
    	nbr->nbr_gr_prefixes = nbr_prefixes;
    	graceful_restart = 1;
    	graceful_restart_final = 0;
    }
    else if((flags == (EIGRP_EOT_FLAG)) && (!same))
	{
		/* If there was INIT+RS Update packet before,
		 *  consider this as GR EOT */

		if(nbr->nbr_gr_prefixes != NULL)
		{
			/* this is final packet of GR */
			nbr_prefixes = nbr->nbr_gr_prefixes;
			nbr->nbr_gr_prefixes = NULL;

			graceful_restart = 1;
			graceful_restart_final = 1;
		}

	}
    else if((flags == (0)) && (!same))
	{
		/* If there was INIT+RS Update packet before,
		 *  consider this as GR not final packet */

		if(nbr->nbr_gr_prefixes != NULL)
		{
			/* this is GR not final route packet */
			nbr_prefixes = nbr->nbr_gr_prefixes;

			graceful_restart = 1;
			graceful_restart_final = 0;
		}

	}
    else if((flags & EIGRP_INIT_FLAG) && (!same))
    {   /* When in pending state, send INIT update only if it wasn't
        already sent before (only if init_sequence is 0) */
        if((nbr->state == EIGRP_NEIGHBOR_PENDING) && (nbr->init_sequence_number == 0))
          eigrp_update_send_init(nbr);

        if (nbr->state == EIGRP_NEIGHBOR_UP)
          {
            eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN);
            eigrp_topology_neighbor_down(nbr->ei->eigrp,nbr);
            nbr->recv_sequence_number = ntohl(eigrph->sequence);
            zlog_info("Neighbor %s (%s) is down: peer restarted",
                      inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
            eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_PENDING);
            zlog_info("Neighbor %s (%s) is pending: new adjacency",
                      inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
            eigrp_update_send_init(nbr);
          }
    }

  /*If there is topology information*/
  while (s->endp > s->getp)
    {
      type = stream_getw(s);
      if (type == EIGRP_TLV_IPv4_INT)
        {
          stream_set_getp(s, s->getp - sizeof(u_int16_t));

          tlv = eigrp_read_ipv4_tlv(s);

          /*searching if destination exists */
          struct prefix_ipv4 *dest_addr;
          dest_addr = prefix_ipv4_new();
          dest_addr->prefix = tlv->destination;
          dest_addr->prefixlen = tlv->prefix_length;
          struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4(
              eigrp->topology_table, dest_addr);

          /*if exists it comes to DUAL*/
          if (dest != NULL)
            {
        	  /* remove received prefix from neighbor prefix list if in GR */
        	  if(graceful_restart)
        		  remove_received_prefix_gr(nbr_prefixes, dest);

              struct eigrp_fsm_action_message *msg;
              msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
                  sizeof(struct eigrp_fsm_action_message));
              struct eigrp_neighbor_entry *entry =
                  eigrp_prefix_entry_lookup(dest->entries, nbr);

              msg->packet_type = EIGRP_OPC_UPDATE;
              msg->eigrp = eigrp;
              msg->data_type = EIGRP_TLV_IPv4_INT;
              msg->adv_router = nbr;
              msg->data.ipv4_int_type = tlv;
              msg->entry = entry;
              msg->prefix = dest;
              int event = eigrp_get_fsm_event(msg);
              eigrp_fsm_event(msg, event);
            }
          else
            {
              /*Here comes topology information save*/
              pe = eigrp_prefix_entry_new();
              pe->serno = eigrp->serno;
              pe->destination_ipv4 = dest_addr;
              pe->af = AF_INET;
              pe->state = EIGRP_FSM_STATE_PASSIVE;
              pe->nt = EIGRP_TOPOLOGY_TYPE_REMOTE;

              ne = eigrp_neighbor_entry_new();
              ne->ei = ei;
              ne->adv_router = nbr;
              ne->reported_metric = tlv->metric;
              ne->reported_distance = eigrp_calculate_metrics(eigrp,
                  &tlv->metric);

              //TODO: Work in progress
              /*
               * Filtering
               */
        	  e = eigrp_lookup();
        	  /* get access-list from eigrp process */
        	  alist = e->list[EIGRP_FILTER_IN];
			  zlog_info("PROC IN Prefix: %s", inet_ntoa(dest_addr->prefix));
			  if (alist) {
				  zlog_info ("ALIST PROC IN: %s", alist->name);
			  } else {
				  zlog_info("ALIST PROC IN je prazdny");
			  }

			  /* Check if access-list fits */
			  if (alist && access_list_apply (alist,
						 (struct prefix *) dest_addr) == FILTER_DENY)
			  {
				  /* If yes, set reported metric to Max */
				  zlog_info("PROC alist IN: Skipping");
				  //ne->reported_metric.delay = EIGRP_MAX_METRIC;
				  zlog_info("PROC IN Prefix: %s", inet_ntoa(dest_addr->prefix));
				  eigrp_IPv4_InternalTLV_free (tlv);
				  continue;
			  } else {
				  zlog_info("PROC alist IN: NENastavujem metriku ");
			  }

			  plist = e->prefix[EIGRP_FILTER_IN];

			  if (plist) {
				  zlog_info ("PLIST PROC IN: %s", plist->name);
			  } else {
				  zlog_info("PLIST PROC IN je prazdny");
			  }

			  /* Check if prefix-list fits */
			  if (plist && prefix_list_apply (plist,
						 (struct prefix *) dest_addr) == FILTER_DENY)
			  {
				  /* If yes, set reported metric to Max */
				  zlog_info("PLIST PROC IN: Skipping");
				  //ne->reported_metric.delay = EIGRP_MAX_METRIC;
				  zlog_info("PLIST PROC IN Prefix: %s", inet_ntoa(dest_addr->prefix));
				  eigrp_IPv4_InternalTLV_free (tlv);
				  continue;
			  } else {
				  zlog_info("PLIST PROC IN: NENastavujem metriku ");
			  }

			  //Check route-map

			  /*if (e->routemap[EIGRP_FILTER_IN])
			  {
			  	 ret = route_map_apply (e->routemap[EIGRP_FILTER_IN],
			  				   (struct prefix *)dest_addr, RMAP_EIGRP, NULL);

			  	 if (ret == RMAP_DENYMATCH)
			  	 {
			  	    zlog_debug ("%s is filtered by route-map",inet_ntoa (dest_addr->prefix));
			  	    continue;
			  	 }
			  }*/

			  /*Get access-list from current interface */
			  zlog_info("Checking access_list on interface: %s",ei->ifp->name);
			  alist = ei->list[EIGRP_FILTER_IN];
			  if (alist) {
			  	  zlog_info ("ALIST INT IN: %s", alist->name);
			  } else {
			  	  zlog_info("ALIST INT IN je prazdny");
			  	}

			  /* Check if access-list fits */
			  if (alist && access_list_apply (alist, (struct prefix *) dest_addr) == FILTER_DENY)
			  {
				  /* If yes, set reported metric to Max */
			  	  zlog_info("INT alist IN: Skipping");
			  	  //ne->reported_metric.delay = EIGRP_MAX_METRIC;
			  	  zlog_info("INT IN Prefix: %s", inet_ntoa(dest_addr->prefix));
			  	  eigrp_IPv4_InternalTLV_free (tlv);
			  	  continue;
			  	} else {
			  	  zlog_info("INT IN: NENastavujem metriku ");
			  }

			  plist = ei->prefix[EIGRP_FILTER_IN];

			  if (plist) {
				  zlog_info ("PLIST INT IN: %s", plist->name);
			  } else {
				  zlog_info("PLIST INT IN je prazdny");
			  }

			  /* Check if prefix-list fits */
			  if (plist && prefix_list_apply (plist,
						 (struct prefix *) dest_addr) == FILTER_DENY)
			  {
				  /* If yes, set reported metric to Max */
				  zlog_info("PLIST INT IN: Skipping");
				  //ne->reported_metric.delay = EIGRP_MAX_METRIC;
				  zlog_info("PLIST INT IN Prefix: %s", inet_ntoa(dest_addr->prefix));
				  eigrp_IPv4_InternalTLV_free (tlv);
				  continue;
			  } else {
				  zlog_info("PLIST INT IN: NENastavujem metriku ");
			  }

			  //Check route-map

			  /*if (ei->routemap[EIGRP_FILTER_IN])
			  {
				 ret = route_map_apply (ei->routemap[EIGRP_FILTER_IN],
							   (struct prefix *)dest_addr, RMAP_EIGRP, NULL);

				 if (ret == RMAP_DENYMATCH)
				 {
					zlog_debug ("%s is filtered by route-map",inet_ntoa (dest_addr->prefix));
					continue;
				 }
			  }*/
			  /*
			   * End of filtering
			   */

			  ne->distance = eigrp_calculate_total_metrics(eigrp, ne);

			  zlog_info("<DEBUG PROC IN Distance: %x", ne->distance);
			  zlog_info("<DEBUG PROC IN Delay: %x", ne->total_metric.delay);

              pe->fdistance = pe->distance = pe->rdistance =
                  ne->distance;
              ne->prefix = pe;
              ne->flags = EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;

              eigrp_prefix_entry_add(eigrp->topology_table, pe);
              eigrp_neighbor_entry_add(pe, ne);
              pe->distance = pe->fdistance = pe->rdistance = ne->distance;
              pe->reported_metric = ne->total_metric;
              eigrp_topology_update_node_flags(pe);

              pe->req_action |= EIGRP_FSM_NEED_UPDATE;
              listnode_add(eigrp->topology_changes_internalIPV4, pe);
            }
          eigrp_IPv4_InternalTLV_free (tlv);
        }
    }

    /* ask about prefixes not present in GR update,
     * if this is final GR packet */
    if(graceful_restart_final)
    {
    	eigrp_update_receive_GR_ask(eigrp, nbr, nbr_prefixes);
    }

  /*
   * We don't need to send separate Ack for INIT Update. INIT will be acked in EOT Update.
   */
  if ((nbr->state == EIGRP_NEIGHBOR_UP) && !(flags == EIGRP_INIT_FLAG))
    {
      eigrp_hello_send_ack(nbr);
    }

  eigrp_query_send_all(eigrp);
  eigrp_update_send_all(eigrp, ei);
}
예제 #11
0
void
ospf6_interface_connected_route_update (struct interface *ifp)
{
  struct ospf6_interface *oi;
  struct ospf6_route *route;
  struct connected *c;
  struct listnode *node, *nnode;

  oi = (struct ospf6_interface *) ifp->info;
  if (oi == NULL)
    return;

  /* reset linklocal pointer */
  oi->linklocal_addr = ospf6_interface_get_linklocal_address (ifp);

  /* if area is null, do not make connected-route list */
  if (oi->area == NULL)
    return;

  /* update "route to advertise" interface route table */
  ospf6_route_remove_all (oi->route_connected);

  for (ALL_LIST_ELEMENTS (oi->interface->connected, node, nnode, c))
    {
      if (c->address->family != AF_INET6)
        continue;

      CONTINUE_IF_ADDRESS_LINKLOCAL (IS_OSPF6_DEBUG_INTERFACE, c->address);
      CONTINUE_IF_ADDRESS_UNSPECIFIED (IS_OSPF6_DEBUG_INTERFACE, c->address);
      CONTINUE_IF_ADDRESS_LOOPBACK (IS_OSPF6_DEBUG_INTERFACE, c->address);
      CONTINUE_IF_ADDRESS_V4COMPAT (IS_OSPF6_DEBUG_INTERFACE, c->address);
      CONTINUE_IF_ADDRESS_V4MAPPED (IS_OSPF6_DEBUG_INTERFACE, c->address);

      /* apply filter */
      if (oi->plist_name)
        {
          struct prefix_list *plist;
          enum prefix_list_type ret;
          char buf[128];

          prefix2str (c->address, buf, sizeof (buf));
          plist = prefix_list_lookup (AFI_IP6, oi->plist_name);
          ret = prefix_list_apply (plist, (void *) c->address);
          if (ret == PREFIX_DENY)
            {
              if (IS_OSPF6_DEBUG_INTERFACE)
                zlog_debug ("%s on %s filtered by prefix-list %s ",
			    buf, oi->interface->name, oi->plist_name);
              continue;
            }
        }

      route = ospf6_route_create ();
      memcpy (&route->prefix, c->address, sizeof (struct prefix));
      apply_mask (&route->prefix);
      route->type = OSPF6_DEST_TYPE_NETWORK;
      route->path.area_id = oi->area->area_id;
      route->path.type = OSPF6_PATH_TYPE_INTRA;
      route->path.cost = oi->cost;
      route->nexthop[0].ifindex = oi->interface->ifindex;
      inet_pton (AF_INET6, "::1", &route->nexthop[0].address);
      ospf6_route_add (route, oi->route_connected);
    }

  /* create new Link-LSA */
  OSPF6_LINK_LSA_SCHEDULE (oi);
  OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi);
  OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area);
}
예제 #12
0
int
babel_filter(int output, const unsigned char *prefix, unsigned short plen,
             unsigned int ifindex)
{
    struct interface *ifp = if_lookup_by_index(ifindex);
    babel_interface_nfo *babel_ifp = ifp ? babel_get_if_nfo(ifp) : NULL;
    struct prefix p;
    struct distribute *dist;
    struct access_list *alist;
    struct prefix_list *plist;
    int filter = output ? BABEL_FILTER_OUT : BABEL_FILTER_IN;
    int distribute = output ? DISTRIBUTE_OUT : DISTRIBUTE_IN;

    p.family = v4mapped(prefix) ? AF_INET : AF_INET6;
    p.prefixlen = v4mapped(prefix) ? plen - 96 : plen;
    if (p.family == AF_INET)
        uchar_to_inaddr(&p.u.prefix4, prefix);
#ifdef HAVE_IPV6
    else
        uchar_to_in6addr(&p.u.prefix6, prefix);
#endif
    if (babel_ifp != NULL && babel_ifp->list[filter]) {
        if (access_list_apply (babel_ifp->list[filter], &p)
            == FILTER_DENY) {
            debugf(BABEL_DEBUG_FILTER,
                   "%s/%d filtered by distribute in",
#ifdef HAVE_IPV6
                   p.family == AF_INET ?
                   inet_ntoa(p.u.prefix4) :
                   inet6_ntoa (p.u.prefix6),
#else
		   inet_ntoa(p.u.prefix4),
#endif
                   p.prefixlen);
            return INFINITY;
	}
    }
    if (babel_ifp != NULL && babel_ifp->prefix[filter]) {
        if (prefix_list_apply (babel_ifp->prefix[filter], &p)
            == PREFIX_DENY) {
            debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in",
#ifdef HAVE_IPV6
                        p.family == AF_INET ?
                        inet_ntoa(p.u.prefix4) :
                        inet6_ntoa (p.u.prefix6),
#else
                        inet_ntoa(p.u.prefix4),
#endif
                        p.prefixlen);
            return INFINITY;
	}
    }

    /* All interface filter check. */
    dist = distribute_lookup (NULL);
    if (dist) {
        if (dist->list[distribute]) {
            alist = access_list_lookup (AFI_IP6, dist->list[distribute]);

            if (alist) {
                if (access_list_apply (alist, &p) == FILTER_DENY) {
                    debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in",
#ifdef HAVE_IPV6
                                p.family == AF_INET ?
                                inet_ntoa(p.u.prefix4) :
                                inet6_ntoa (p.u.prefix6),
#else
                                inet_ntoa(p.u.prefix4),
#endif
                                p.prefixlen);
                    return INFINITY;
		}
	    }
	}
        if (dist->prefix[distribute]) {
            plist = prefix_list_lookup (AFI_IP6, dist->prefix[distribute]);
            if (plist) {
                if (prefix_list_apply (plist, &p) == PREFIX_DENY) {
                    debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in",
#ifdef HAVE_IPV6
                                p.family == AF_INET ?
                                inet_ntoa(p.u.prefix4) :
                                inet6_ntoa (p.u.prefix6),
#else
                                inet_ntoa(p.u.prefix4),
#endif
                                p.prefixlen);
                    return INFINITY;
		}
	    }
	}
    }
    return 0;
}
예제 #13
0
/* RFC 2328 16.2. Calculating the inter-area routes */
void
ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
{
  struct prefix prefix, abr_prefix;
  struct ospf6_route_table *table = NULL;
  struct ospf6_route *range, *route, *old = NULL;
  struct ospf6_route *abr_entry;
  u_char type = 0;
  char options[3] = {0, 0, 0};
  u_int8_t prefix_options = 0;
  u_int32_t cost = 0;
  u_char router_bits = 0;
  int i;
  char buf[64];
  int is_debug = 0;
  struct ospf6_inter_prefix_lsa *prefix_lsa = NULL;
  struct ospf6_inter_router_lsa *router_lsa = NULL;

  memset (&prefix, 0, sizeof (prefix));

  if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_PREFIX))
    {
      if (IS_OSPF6_DEBUG_EXAMIN (INTER_PREFIX))
        {
          is_debug++;
          zlog_debug ("Examin %s in area %s", lsa->name, oa->name);
        }

      prefix_lsa = (struct ospf6_inter_prefix_lsa *)
        OSPF6_LSA_HEADER_END (lsa->header);
      prefix.family = AF_INET6;
      prefix.prefixlen = prefix_lsa->prefix.prefix_length;
      ospf6_prefix_in6_addr (&prefix.u.prefix6, &prefix_lsa->prefix);
      if (is_debug)
        prefix2str (&prefix, buf, sizeof (buf));
      table = oa->ospf6->route_table;
      type = OSPF6_DEST_TYPE_NETWORK;
      prefix_options = prefix_lsa->prefix.prefix_options;
      cost = OSPF6_ABR_SUMMARY_METRIC (prefix_lsa);
    }
  else if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_ROUTER))
    {
      if (IS_OSPF6_DEBUG_EXAMIN (INTER_ROUTER))
        {
          is_debug++;
          zlog_debug ("Examin %s in area %s", lsa->name, oa->name);
        }

      router_lsa = (struct ospf6_inter_router_lsa *)
        OSPF6_LSA_HEADER_END (lsa->header);
      ospf6_linkstate_prefix (router_lsa->router_id, htonl (0), &prefix);
      if (is_debug)
        inet_ntop (AF_INET, &router_lsa->router_id, buf, sizeof (buf));
      table = oa->ospf6->brouter_table;
      type = OSPF6_DEST_TYPE_ROUTER;
      options[0] = router_lsa->options[0];
      options[1] = router_lsa->options[1];
      options[2] = router_lsa->options[2];
      cost = OSPF6_ABR_SUMMARY_METRIC (router_lsa);
      SET_FLAG (router_bits, OSPF6_ROUTER_BIT_E);
    }
  else
    assert (0);

  /* Find existing route */
  route = ospf6_route_lookup (&prefix, table);
  if (route)
    ospf6_route_lock (route);
  while (route && ospf6_route_is_prefix (&prefix, route))
    {
      if (route->path.area_id == oa->area_id &&
          route->path.origin.type == lsa->header->type &&
          route->path.origin.id == lsa->header->id &&
          route->path.origin.adv_router == lsa->header->adv_router &&
          ! CHECK_FLAG (route->flag, OSPF6_ROUTE_WAS_REMOVED))
        old = route;
      route = ospf6_route_next (route);
    }

  /* (1) if cost == LSInfinity or if the LSA is MaxAge */
  if (cost == OSPF_LS_INFINITY)
    {
      if (is_debug)
        zlog_debug ("cost is LS_INFINITY, ignore");
      if (old)
        ospf6_route_remove (old, table);
      return;
    }
  if (OSPF6_LSA_IS_MAXAGE (lsa))
    {
      if (is_debug)
        zlog_debug ("LSA is MaxAge, ignore");
      if (old)
        ospf6_route_remove (old, table);
      return;
    }

  /* (2) if the LSA is self-originated, ignore */
  if (lsa->header->adv_router == oa->ospf6->router_id)
    {
      if (is_debug)
        zlog_debug ("LSA is self-originated, ignore");
      if (old)
        ospf6_route_remove (old, table);
      return;
    }

  /* (3) if the prefix is equal to an active configured address range */
  /*     or if the NU bit is set in the prefix */
  if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_PREFIX))
    {
      range = ospf6_route_lookup (&prefix, oa->range_table);
      if (range)
        {
          if (is_debug)
            zlog_debug ("Prefix is equal to address range, ignore");
          if (old)
            ospf6_route_remove (old, table);
          return;
        }

      if (CHECK_FLAG (prefix_lsa->prefix.prefix_options,
		      OSPF6_PREFIX_OPTION_NU) ||
	  CHECK_FLAG (prefix_lsa->prefix.prefix_options,
		      OSPF6_PREFIX_OPTION_LA))
	{
          if (is_debug)
            zlog_debug ("Prefix has NU/LA bit set, ignore");
          if (old)
            ospf6_route_remove (old, table);
          return;
	}
    }

  if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_ROUTER))
    {
      /* To pass test suites */
      if (! OSPF6_OPT_ISSET (router_lsa->options, OSPF6_OPT_R) ||
	  ! OSPF6_OPT_ISSET (router_lsa->options, OSPF6_OPT_V6))
	{
          if (is_debug)
            zlog_debug ("Prefix has NU/LA bit set, ignore");
          if (old)
            ospf6_route_remove (old, table);
          return;
	}
    }

  /* (4) if the routing table entry for the ABR does not exist */
  ospf6_linkstate_prefix (lsa->header->adv_router, htonl (0), &abr_prefix);
  abr_entry = ospf6_route_lookup (&abr_prefix, oa->ospf6->brouter_table);
  if (abr_entry == NULL || abr_entry->path.area_id != oa->area_id ||
      CHECK_FLAG (abr_entry->flag, OSPF6_ROUTE_REMOVE) ||
      ! CHECK_FLAG (abr_entry->path.router_bits, OSPF6_ROUTER_BIT_B))
    {
      if (is_debug)
        zlog_debug ("ABR router entry does not exist, ignore");
      if (old)
        ospf6_route_remove (old, table);
      return;
    }

  /* Check import list */
  if (IMPORT_NAME (oa))
    {
      if (IMPORT_LIST (oa) == NULL)
        IMPORT_LIST (oa) = access_list_lookup (AFI_IP6, IMPORT_NAME (oa));

      if (IMPORT_LIST (oa))
        if (access_list_apply (IMPORT_LIST (oa), &prefix) == FILTER_DENY)
          {
            if (is_debug)
              zlog_debug ("Prefix was denied by import-list");
            if (old)
              ospf6_route_remove (old, table);
            return;
          }
    }

  /* Check input prefix-list */
  if (PREFIX_NAME_IN (oa))
    {
      if (PREFIX_LIST_IN (oa) == NULL)
        PREFIX_LIST_IN (oa) = prefix_list_lookup (AFI_IP6, PREFIX_NAME_IN (oa));

      if (PREFIX_LIST_IN (oa))
        if (prefix_list_apply (PREFIX_LIST_IN (oa), &prefix) != PREFIX_PERMIT)
          {
            if (is_debug)
              zlog_debug ("Prefix was denied by prefix-list");
            if (old)
              ospf6_route_remove (old, table);
            return;
          }
    }

  /* (5),(6),(7) the path preference is handled by the sorting
     in the routing table. Always install the path by substituting
     old route (if any). */
  if (old)
    route = ospf6_route_copy (old);
  else
    route = ospf6_route_create ();

  route->type = type;
  route->prefix = prefix;
  route->path.origin.type = lsa->header->type;
  route->path.origin.id = lsa->header->id;
  route->path.origin.adv_router = lsa->header->adv_router;
  route->path.router_bits = router_bits;
  route->path.options[0] = options[0];
  route->path.options[1] = options[1];
  route->path.options[2] = options[2];
  route->path.prefix_options = prefix_options;
  route->path.area_id = oa->area_id;
  route->path.type = OSPF6_PATH_TYPE_INTER;
  route->path.cost = abr_entry->path.cost + cost;
  for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
    route->nexthop[i] = abr_entry->nexthop[i];

  if (is_debug)
    zlog_debug ("Install route: %s", buf);
  ospf6_route_add (route, table);
}
예제 #14
0
/* RFC 2328 12.4.3. Summary-LSAs */
void
ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
                                     struct ospf6_area *area)
{
  struct ospf6_lsa *lsa, *old = NULL;
  struct ospf6_interface *oi;
  struct ospf6_route *summary, *range = NULL;
  struct ospf6_area *route_area;
  char buffer[OSPF6_MAX_LSASIZE];
  struct ospf6_lsa_header *lsa_header;
  caddr_t p;
  struct ospf6_inter_prefix_lsa *prefix_lsa;
  struct ospf6_inter_router_lsa *router_lsa;
  struct ospf6_route_table *summary_table = NULL;
  u_int16_t type;
  char buf[64];
  int is_debug = 0;

  if (route->type == OSPF6_DEST_TYPE_ROUTER)
    {
      if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_ORIGINATE (INTER_ROUTER))
        {
          is_debug++;
          inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)),
                     buf, sizeof (buf));
          zlog_debug ("Originating summary in area %s for ASBR %s",
		      area->name, buf);
        }
      summary_table = area->summary_router;
    }
  else
    {
      if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_ORIGINATE (INTER_PREFIX))
        {
          is_debug++;
          prefix2str (&route->prefix, buf, sizeof (buf));
          zlog_debug ("Originating summary in area %s for %s",
		      area->name, buf);
        }
      summary_table = area->summary_prefix;
    }

  summary = ospf6_route_lookup (&route->prefix, summary_table);
  if (summary)
    old = ospf6_lsdb_lookup (summary->path.origin.type,
                             summary->path.origin.id,
                             area->ospf6->router_id, area->lsdb);

  /* if this route has just removed, remove corresponding LSA */
  if (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE))
    {
      if (is_debug)
        zlog_debug ("The route has just removed, purge previous LSA");
      if (summary)
        ospf6_route_remove (summary, summary_table);
      if (old)
        ospf6_lsa_purge (old);
      return;
    }

  /* Only destination type network, range or ASBR are considered */
  if (route->type != OSPF6_DEST_TYPE_NETWORK &&
      route->type != OSPF6_DEST_TYPE_RANGE &&
      (route->type != OSPF6_DEST_TYPE_ROUTER ||
       ! CHECK_FLAG (route->path.router_bits, OSPF6_ROUTER_BIT_E)))
    {
      if (is_debug)
        zlog_debug ("Route type is none of network, range nor ASBR, withdraw");
      if (summary)
        ospf6_route_remove (summary, summary_table);
      if (old)
        ospf6_lsa_purge (old);
      return;
    }

  /* AS External routes are never considered */
  if (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1 ||
      route->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
    {
      if (is_debug)
        zlog_debug ("Path type is external, withdraw");
      if (summary)
        ospf6_route_remove (summary, summary_table);
      if (old)
        ospf6_lsa_purge (old);
      return;
    }

  /* do not generate if the path's area is the same as target area */
  if (route->path.area_id == area->area_id)
    {
      if (is_debug)
        zlog_debug ("The route is in the area itself, ignore");
      if (summary)
        ospf6_route_remove (summary, summary_table);
      if (old)
        ospf6_lsa_purge (old);
      return;
    }

  /* do not generate if the nexthops belongs to the target area */
  oi = ospf6_interface_lookup_by_ifindex (route->nexthop[0].ifindex);
  if (oi && oi->area && oi->area == area)
    {
      if (is_debug)
        zlog_debug ("The route's nexthop is in the same area, ignore");
      if (summary)
        ospf6_route_remove (summary, summary_table);
      if (old)
        ospf6_lsa_purge (old);
      return;
    }

  /* do not generate if the route cost is greater or equal to LSInfinity */
  if (route->path.cost >= OSPF_LS_INFINITY)
    {
      if (is_debug)
        zlog_debug ("The cost exceeds LSInfinity, withdraw");
      if (summary)
        ospf6_route_remove (summary, summary_table);
      if (old)
        ospf6_lsa_purge (old);
      return;
    }

  /* if this is a route to ASBR */
  if (route->type == OSPF6_DEST_TYPE_ROUTER)
    {
      /* Only the prefered best path is considered */
      if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_BEST))
        {
          if (is_debug)
            zlog_debug ("This is the secondary path to the ASBR, ignore");
          if (summary)
            ospf6_route_remove (summary, summary_table);
          if (old)
            ospf6_lsa_purge (old);
          return;
        }

      /* Do not generate if the area is stub */
      /* XXX */
    }

  /* if this is an intra-area route, this may be suppressed by aggregation */
  if (route->type == OSPF6_DEST_TYPE_NETWORK &&
      route->path.type == OSPF6_PATH_TYPE_INTRA)
    {
      /* search for configured address range for the route's area */
      route_area = ospf6_area_lookup (route->path.area_id, area->ospf6);
      assert (route_area);
      range = ospf6_route_lookup_bestmatch (&route->prefix,
                                            route_area->range_table);

      /* ranges are ignored when originate backbone routes to transit area.
         Otherwise, if ranges are configured, the route is suppressed. */
      if (range && ! CHECK_FLAG (range->flag, OSPF6_ROUTE_REMOVE) &&
          (route->path.area_id != OSPF_AREA_BACKBONE ||
           ! IS_AREA_TRANSIT (area)))
        {
          if (is_debug)
            {
              prefix2str (&range->prefix, buf, sizeof (buf));
              zlog_debug ("Suppressed by range %s of area %s",
                         buf, route_area->name);
            }

          if (summary)
            ospf6_route_remove (summary, summary_table);
          if (old)
            ospf6_lsa_purge (old);
          return;
        }
    }

  /* If this is a configured address range */
  if (route->type == OSPF6_DEST_TYPE_RANGE)
    {
      /* If DoNotAdvertise is set */
      if (CHECK_FLAG (route->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE))
        {
          if (is_debug)
            zlog_debug ("This is the range with DoNotAdvertise set. ignore");
          if (summary)
            ospf6_route_remove (summary, summary_table);
          if (old)
            ospf6_lsa_purge (old);
          return;
        }

      /* Whether the route have active longer prefix */
      if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_ACTIVE_SUMMARY))
        {
          if (is_debug)
            zlog_debug ("The range is not active. withdraw");
          if (summary)
            ospf6_route_remove (summary, summary_table);
          if (old)
            ospf6_lsa_purge (old);
          return;
        }
    }

  /* Check export list */
  if (EXPORT_NAME (area))
    {
      if (EXPORT_LIST (area) == NULL)
        EXPORT_LIST (area) =
          access_list_lookup (AFI_IP6, EXPORT_NAME (area));

      if (EXPORT_LIST (area))
        if (access_list_apply (EXPORT_LIST (area),
                               &route->prefix) == FILTER_DENY)
          {
            if (is_debug)
              {
                inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)),
                           buf, sizeof(buf));
                zlog_debug ("prefix %s was denied by export list", buf);
              }
            return;
          }
    }

  /* Check filter-list */
  if (PREFIX_NAME_OUT (area))
    {
      if (PREFIX_LIST_OUT (area) == NULL)
        PREFIX_LIST_OUT (area) =
          prefix_list_lookup(AFI_IP6, PREFIX_NAME_OUT (area));

      if (PREFIX_LIST_OUT (area))
         if (prefix_list_apply (PREFIX_LIST_OUT (area), 
                                &route->prefix) != PREFIX_PERMIT) 
           {
             if (is_debug)
               {
                 inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)),
                            buf, sizeof (buf));
                 zlog_debug ("prefix %s was denied by filter-list out", buf);
               }
             return;
           }
    }

  /* the route is going to be originated. store it in area's summary_table */
  if (summary == NULL)
    {
      summary = ospf6_route_copy (route);
      if (route->type == OSPF6_DEST_TYPE_NETWORK ||
          route->type == OSPF6_DEST_TYPE_RANGE)
        summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_PREFIX);
      else
        summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_ROUTER);
      summary->path.origin.adv_router = area->ospf6->router_id;
      summary->path.origin.id =
        ospf6_new_ls_id (summary->path.origin.type,
                         summary->path.origin.adv_router, area->lsdb);
      summary = ospf6_route_add (summary, summary_table);
    }
  else
    {
      summary->type = route->type;
      quagga_gettime (QUAGGA_CLK_MONOTONIC, &summary->changed);
    }

  summary->path.router_bits = route->path.router_bits;
  summary->path.options[0] = route->path.options[0];
  summary->path.options[1] = route->path.options[1];
  summary->path.options[2] = route->path.options[2];
  summary->path.prefix_options = route->path.prefix_options;
  summary->path.area_id = area->area_id;
  summary->path.type = OSPF6_PATH_TYPE_INTER;
  summary->path.cost = route->path.cost;
  summary->nexthop[0] = route->nexthop[0];

  /* prepare buffer */
  memset (buffer, 0, sizeof (buffer));
  lsa_header = (struct ospf6_lsa_header *) buffer;

  if (route->type == OSPF6_DEST_TYPE_ROUTER)
    {
      router_lsa = (struct ospf6_inter_router_lsa *)
        ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header));
      p = (caddr_t) router_lsa + sizeof (struct ospf6_inter_router_lsa);

      /* Fill Inter-Area-Router-LSA */
      router_lsa->options[0] = route->path.options[0];
      router_lsa->options[1] = route->path.options[1];
      router_lsa->options[2] = route->path.options[2];
      OSPF6_ABR_SUMMARY_METRIC_SET (router_lsa, route->path.cost);
      router_lsa->router_id = ADV_ROUTER_IN_PREFIX (&route->prefix);
      type = htons (OSPF6_LSTYPE_INTER_ROUTER);
    }
  else
    {
      prefix_lsa = (struct ospf6_inter_prefix_lsa *)
        ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header));
      p = (caddr_t) prefix_lsa + sizeof (struct ospf6_inter_prefix_lsa);

      /* Fill Inter-Area-Prefix-LSA */
      OSPF6_ABR_SUMMARY_METRIC_SET (prefix_lsa, route->path.cost);
      prefix_lsa->prefix.prefix_length = route->prefix.prefixlen;
      prefix_lsa->prefix.prefix_options = route->path.prefix_options;

      /* set Prefix */
      memcpy (p, &route->prefix.u.prefix6,
              OSPF6_PREFIX_SPACE (route->prefix.prefixlen));
      ospf6_prefix_apply_mask (&prefix_lsa->prefix);
      p += OSPF6_PREFIX_SPACE (route->prefix.prefixlen);
      type = htons (OSPF6_LSTYPE_INTER_PREFIX);
    }

  /* Fill LSA Header */
  lsa_header->age = 0;
  lsa_header->type = type;
  lsa_header->id = summary->path.origin.id;
  lsa_header->adv_router = area->ospf6->router_id;
  lsa_header->seqnum =
    ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id,
                         lsa_header->adv_router, area->lsdb);
  lsa_header->length = htons ((caddr_t) p - (caddr_t) lsa_header);

  /* LSA checksum */
  ospf6_lsa_checksum (lsa_header);

  /* create LSA */
  lsa = ospf6_lsa_create (lsa_header);

  /* Originate */
  ospf6_lsa_originate_area (lsa, area);
}