Ejemplo n.º 1
0
/* If nexthop exists on connected network return 1. */
int
bgp_nexthop_onlink (afi_t afi, struct attr *attr)
{
  struct bgp_node *rn;
  
  /* Lookup the address is onlink or not. */
  if (afi == AFI_IP)
    {
      rn = bgp_node_match_ipv4 (bgp_connected_table[AFI_IP], &attr->nexthop);
      if (rn)
	{
	  bgp_unlock_node (rn);
	  return 1;
	}
    }
  else if (afi == AFI_IP6)
    {
      if (attr->extra->mp_nexthop_len == 32)
	return 1;
      else if (attr->extra->mp_nexthop_len == 16)
	{
	  if (IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_global))
	    return 1;

	  rn = bgp_node_match_ipv6 (bgp_connected_table[AFI_IP6],
				      &attr->extra->mp_nexthop_global);
	  if (rn)
	    {
	      bgp_unlock_node (rn);
	      return 1;
	    }
	}
    }
  return 0;
}
Ejemplo n.º 2
0
/* If nexthop exists on connected network return 1. */
int
bgp_nexthop_onlink (afi_t afi, struct attr *attr)
{
  struct bgp_node *rn;
  
  /* If zebra is not enabled return */
  if (zlookup->sock < 0)
    return 1;
  
  /* Lookup the address is onlink or not. */
  if (afi == AFI_IP)
    {
      rn = bgp_node_match_ipv4 (bgp_connected_table[AFI_IP], &attr->nexthop);
      if (rn)
	{
	  bgp_unlock_node (rn);
	  return 1;
	}
    }
#ifdef HAVE_IPV6
  else if (afi == AFI_IP6)
    {
      if (attr->extra->mp_nexthop_len == 32)
	return 1;
      else if (attr->extra->mp_nexthop_len == 16)
	{
	  if (IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_global))
	    return 1;

	  rn = bgp_node_match_ipv6 (bgp_connected_table[AFI_IP6],
				      &attr->extra->mp_nexthop_global);
	  if (rn)
	    {
	      bgp_unlock_node (rn);
	      return 1;
	    }
	}
    }
#endif /* HAVE_IPV6 */
  return 0;
}
Ejemplo n.º 3
0
void bgp_follow_nexthop_lookup(struct packet_ptrs *pptrs)
{
  struct sockaddr *sa = (struct sockaddr *) pptrs->f_agent, sa_local;
  struct bgp_peer *nh_peer;
  struct bgp_node *result_node = NULL;
  struct bgp_info *info;
  char *result = NULL, *saved_info = NULL;
  int peers_idx, ttl = MAX_HOPS_FOLLOW_NH, self = MAX_NH_SELF_REFERENCES;
  int nh_idx, matched = 0;
  struct prefix nh, ch;
  struct in_addr pref4;
#if defined ENABLE_IPV6
  struct in6_addr pref6;
#endif
  char *saved_agent = pptrs->f_agent;
  pm_id_t bta;
  u_int32_t modulo, local_modulo, modulo_idx, modulo_max;

  start_again:

  if (config.nfacctd_bgp_to_agent_map && (*find_id_func)) {
    bta = 0;
    (*find_id_func)((struct id_table *)pptrs->bta_table, pptrs, &bta, NULL);
    if (bta) {
      sa = &sa_local;
      sa->sa_family = AF_INET;
      ((struct sockaddr_in *)sa)->sin_addr.s_addr = bta;
    }
  }

  for (nh_peer = NULL, peers_idx = 0; peers_idx < config.nfacctd_bgp_max_peers; peers_idx++) {
    if (!sa_addr_cmp(sa, &peers[peers_idx].addr) || !sa_addr_cmp(sa, &peers[peers_idx].id)) {
      nh_peer = &peers[peers_idx];
      break;
    }
  }

  if (nh_peer) {
    modulo = bgp_route_info_modulo(nh_peer, NULL);

    // XXX: to be optimized 
    if (config.bgp_table_per_peer_hash == BGP_ASPATH_HASH_PATHID) modulo_max = config.bgp_table_per_peer_buckets;
    else modulo_max = 1;

    memset(&ch, 0, sizeof(ch));
    ch.family = AF_INET;
    ch.prefixlen = 32;
    memcpy(&ch.u.prefix4, &nh_peer->addr.address.ipv4, 4);

    if (!result) {
      if (pptrs->l3_proto == ETHERTYPE_IP) {
        memcpy(&pref4, &((struct my_iphdr *)pptrs->iph_ptr)->ip_dst, sizeof(struct in_addr));
        result = (char *) bgp_node_match_ipv4(bgp_routing_db->rib[AFI_IP][SAFI_UNICAST], &pref4, nh_peer);
      }
#if defined ENABLE_IPV6
      else if (pptrs->l3_proto == ETHERTYPE_IPV6) {
        memcpy(&pref6, &((struct ip6_hdr *)pptrs->iph_ptr)->ip6_dst, sizeof(struct in6_addr));
        result = (char *) bgp_node_match_ipv6(bgp_routing_db->rib[AFI_IP6][SAFI_UNICAST], &pref6, nh_peer);
      }
#endif
    }

    memset(&nh, 0, sizeof(nh));
    result_node = (struct bgp_node *) result;

    if (result_node) {
      for (local_modulo = modulo, modulo_idx = 0; modulo_idx < modulo_max; local_modulo++, modulo_idx++) {
        for (info = result_node->info[modulo]; info; info = info->next) {
          if (info->peer == nh_peer) break;
	}
      }
    }
    else info = NULL;

    if (info && info->attr) {
      if (info->attr->mp_nexthop.family == AF_INET) {
	nh.family = AF_INET;
	nh.prefixlen = 32;
	memcpy(&nh.u.prefix4, &info->attr->mp_nexthop.address.ipv4, 4);

	for (nh_idx = 0; config.nfacctd_bgp_follow_nexthop[nh_idx].family && nh_idx < FOLLOW_BGP_NH_ENTRIES; nh_idx++) {
	  matched = prefix_match(&config.nfacctd_bgp_follow_nexthop[nh_idx], &nh);
	  if (matched) break;
	}

	if (matched && self > 0 && ttl > 0) { 
	  if (prefix_match(&ch, &nh)) self--;
          sa = &sa_local;
          pptrs->f_agent = (char *) &sa_local;
          memset(sa, 0, sizeof(struct sockaddr));
          sa->sa_family = AF_INET;
          memcpy(&((struct sockaddr_in *)sa)->sin_addr, &info->attr->mp_nexthop.address.ipv4, 4);
	  saved_info = (char *) info;
	  ttl--;
          goto start_again;
        }
	else goto end;
      }
#if defined ENABLE_IPV6
      else if (info->attr->mp_nexthop.family == AF_INET6) {
	nh.family = AF_INET6;
	nh.prefixlen = 128;
	memcpy(&nh.u.prefix6, &info->attr->mp_nexthop.address.ipv6, 16);

        for (nh_idx = 0; config.nfacctd_bgp_follow_nexthop[nh_idx].family && nh_idx < FOLLOW_BGP_NH_ENTRIES; nh_idx++) {
          matched = prefix_match(&config.nfacctd_bgp_follow_nexthop[nh_idx], &nh);
          if (matched) break;
        }

	if (matched && self > 0 && ttl > 0) {
	  if (prefix_match(&ch, &nh)) self--;
          sa = &sa_local;
          pptrs->f_agent = (char *) &sa_local;
          memset(sa, 0, sizeof(struct sockaddr));
          sa->sa_family = AF_INET6;
          ip6_addr_cpy(&((struct sockaddr_in6 *)sa)->sin6_addr, &info->attr->mp_nexthop.address.ipv6);
	  saved_info = (char *) info;
	  ttl--;
          goto start_again;
	}
	else goto end;
      }
#endif
      else {
	nh.family = AF_INET;
	nh.prefixlen = 32;
	memcpy(&nh.u.prefix4, &info->attr->nexthop, 4);

        for (nh_idx = 0; config.nfacctd_bgp_follow_nexthop[nh_idx].family && nh_idx < FOLLOW_BGP_NH_ENTRIES; nh_idx++) {
          matched = prefix_match(&config.nfacctd_bgp_follow_nexthop[nh_idx], &nh);
          if (matched) break;
        }

	if (matched && self > 0 && ttl > 0) {
	  if (prefix_match(&ch, &nh)) self--;
          sa = &sa_local;
          pptrs->f_agent = (char *) &sa_local;
          memset(sa, 0, sizeof(struct sockaddr));
          sa->sa_family = AF_INET;
          memcpy(&((struct sockaddr_in *)sa)->sin_addr, &info->attr->nexthop, 4);
	  saved_info = (char *) info;
	  ttl--;
          goto start_again;
	}
	else goto end;
      }
    }
  }

  end:

  if (saved_info) pptrs->bgp_nexthop_info = saved_info; 
  pptrs->f_agent = saved_agent;
}
Ejemplo n.º 4
0
void bgp_srcdst_lookup(struct packet_ptrs *pptrs)
{
  struct sockaddr *sa = (struct sockaddr *) pptrs->f_agent, sa_local;
  struct xflow_status_entry *xs_entry = (struct xflow_status_entry *) pptrs->f_status;
  struct bgp_peer *peer;
  struct bgp_node *default_node, *result;
  struct bgp_info *info;
  struct prefix default_prefix;
  int peers_idx, compare_bgp_port;
  int follow_default = config.nfacctd_bgp_follow_default;
  struct in_addr pref4;
#if defined ENABLE_IPV6
  struct in6_addr pref6;
#endif
  u_int32_t modulo, local_modulo, modulo_idx, modulo_max;
  u_int32_t peer_idx, *peer_idx_ptr;
  safi_t safi;
  rd_t rd;

  pptrs->bgp_src = NULL;
  pptrs->bgp_dst = NULL;
  pptrs->bgp_src_info = NULL;
  pptrs->bgp_dst_info = NULL;
  pptrs->bgp_peer = NULL;
  pptrs->bgp_nexthop_info = NULL;
  compare_bgp_port = FALSE;
  safi = SAFI_UNICAST;

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

  if (pptrs->bta) {
    sa = &sa_local;
    if (pptrs->bta_af == ETHERTYPE_IP) {
      sa->sa_family = AF_INET;
      ((struct sockaddr_in *)sa)->sin_addr.s_addr = pptrs->bta; 
      if (pptrs->lookup_bgp_port.set) {
	((struct sockaddr_in *)sa)->sin_port = pptrs->lookup_bgp_port.n; 
	compare_bgp_port = TRUE;
      }
    }
#if defined ENABLE_IPV6
    else if (pptrs->bta_af == ETHERTYPE_IPV6) {
      sa->sa_family = AF_INET6;
      ip6_addr_32bit_cpy(&((struct sockaddr_in6 *)sa)->sin6_addr, &pptrs->bta, 0, 0, 1);
      ip6_addr_32bit_cpy(&((struct sockaddr_in6 *)sa)->sin6_addr, &pptrs->bta2, 2, 0, 1);
      if (pptrs->lookup_bgp_port.set) {
        ((struct sockaddr_in6 *)sa)->sin6_port = pptrs->lookup_bgp_port.n; 
	compare_bgp_port = TRUE;
      }
    }
#endif
  }

  start_again:

  peer_idx = 0; peer_idx_ptr = NULL;
  if (xs_entry) {
    if (pptrs->l3_proto == ETHERTYPE_IP) {
      peer_idx = xs_entry->peer_v4_idx; 
      peer_idx_ptr = &xs_entry->peer_v4_idx;
    }
#if defined ENABLE_IPV6
    else if (pptrs->l3_proto == ETHERTYPE_IPV6) {
      peer_idx = xs_entry->peer_v6_idx; 
      peer_idx_ptr = &xs_entry->peer_v6_idx;
    }
#endif
  }

  if (xs_entry && peer_idx) {
    if ((!sa_addr_cmp(sa, &peers[peer_idx].addr) || !sa_addr_cmp(sa, &peers[peer_idx].id)) &&
        (!compare_bgp_port || !sa_port_cmp(sa, peers[peer_idx].tcp_port))) {
      peer = &peers[peer_idx];
      pptrs->bgp_peer = (char *) &peers[peer_idx];
    }
    /* If no match then let's invalidate the entry */
    else {
      *peer_idx_ptr = 0;
      peer = NULL;
    }
  }
  else {
    for (peer = NULL, peers_idx = 0; peers_idx < config.nfacctd_bgp_max_peers; peers_idx++) {
      if ((!sa_addr_cmp(sa, &peers[peers_idx].addr) || !sa_addr_cmp(sa, &peers[peers_idx].id)) && 
	  (!compare_bgp_port || !sa_port_cmp(sa, peers[peer_idx].tcp_port))) {
        peer = &peers[peers_idx];
        pptrs->bgp_peer = (char *) &peers[peers_idx];
        if (xs_entry && peer_idx_ptr) *peer_idx_ptr = peers_idx;
        break;
      }
    }
  }

  if (peer) {
    struct host_addr peer_dst_ip;

    modulo = bgp_route_info_modulo(peer, NULL);

    // XXX: to be optimized 
    if (config.bgp_table_per_peer_hash == BGP_ASPATH_HASH_PATHID) modulo_max = config.bgp_table_per_peer_buckets; 
    else modulo_max = 1;

    if (peer->cap_add_paths && (config.acct_type == ACCT_NF || config.acct_type == ACCT_SF)) {
      /* administrativia */
      struct pkt_bgp_primitives pbgp, *pbgp_ptr = &pbgp;
      memset(&pbgp, 0, sizeof(struct pkt_bgp_primitives));
      
      /* note: call to [NF|SF]_peer_dst_ip_handler for the purpose of
	 code re-use effectively is defeating the concept of libbgp */
      if (config.acct_type == ACCT_NF) NF_peer_dst_ip_handler(NULL, pptrs, &pbgp_ptr);
      else if (config.acct_type == ACCT_SF) SF_peer_dst_ip_handler(NULL, pptrs, &pbgp_ptr);

      memcpy(&peer_dst_ip, &pbgp.peer_dst_ip, sizeof(struct host_addr));
    }

    if (pptrs->bitr) {
      safi = SAFI_MPLS_VPN;
      memcpy(&rd, &pptrs->bitr, sizeof(rd));
    }

    if (pptrs->l3_proto == ETHERTYPE_IP) {
      if (!pptrs->bgp_src) {
        memcpy(&pref4, &((struct my_iphdr *)pptrs->iph_ptr)->ip_src, sizeof(struct in_addr));
	pptrs->bgp_src = (char *) bgp_node_match_ipv4(bgp_routing_db->rib[AFI_IP][safi],
						      &pref4, (struct bgp_peer *) pptrs->bgp_peer);
      }
      if (!pptrs->bgp_src_info && pptrs->bgp_src) {
	result = (struct bgp_node *) pptrs->bgp_src;	
        if (result->p.prefixlen >= pptrs->lm_mask_src) {
          pptrs->lm_mask_src = result->p.prefixlen;
          pptrs->lm_method_src = NF_NET_BGP;
        }

	for (info = result->info[modulo]; info; info = info->next) {
	  if (safi != SAFI_MPLS_VPN) {
	    if (info->peer == peer) {
	      pptrs->bgp_src_info = (char *) info;
	      break;
	    }
	  }
	  else {
	    if (info->peer == peer && info->extra && !memcmp(&info->extra->rd, &rd, sizeof(rd_t))) {
	      pptrs->bgp_src_info = (char *) info;
	      break;
	    }
	  }
	}
      }
      if (!pptrs->bgp_dst) {
	memcpy(&pref4, &((struct my_iphdr *)pptrs->iph_ptr)->ip_dst, sizeof(struct in_addr));
	pptrs->bgp_dst = (char *) bgp_node_match_ipv4(bgp_routing_db->rib[AFI_IP][safi],
						      &pref4, (struct bgp_peer *) pptrs->bgp_peer);
      }
      if (!pptrs->bgp_dst_info && pptrs->bgp_dst) {
	result = (struct bgp_node *) pptrs->bgp_dst;
        if (result->p.prefixlen >= pptrs->lm_mask_dst) {
          pptrs->lm_mask_dst = result->p.prefixlen;
          pptrs->lm_method_dst = NF_NET_BGP;
        }

        for (local_modulo = modulo, modulo_idx = 0; modulo_idx < modulo_max; local_modulo++, modulo_idx++) {
          for (info = result->info[local_modulo]; info; info = info->next) {
	    if (info->peer == peer) {
	      int no_match = FALSE;

	      /* flagging additional checks are required */
	      if (safi == SAFI_MPLS_VPN) no_match++;
	      if (peer->cap_add_paths) no_match++;
 
	      if (safi == SAFI_MPLS_VPN) {
	        if (info->extra && !memcmp(&info->extra->rd, &rd, sizeof(rd_t))) no_match--;
	      }

	      if (peer->cap_add_paths) {
	        if (info->attr) {
		  if (info->attr->mp_nexthop.family == peer_dst_ip.family) {
		    if (!memcmp(&info->attr->mp_nexthop, &peer_dst_ip, HostAddrSz)) no_match--;
		  }
		  else if (info->attr->nexthop.s_addr && peer_dst_ip.family == AF_INET) {
		    if (info->attr->nexthop.s_addr == peer_dst_ip.address.ipv4.s_addr) no_match--;
		  }
	        }
	      }

	      if (!no_match) {
	        pptrs->bgp_dst_info = (char *) info;
	        break;
	      }
	    }
	  }

	  /* if having results, let's not potentially look in other buckets */
	  if (pptrs->bgp_dst_info) break;
        }
      }
    }
#if defined ENABLE_IPV6
    else if (pptrs->l3_proto == ETHERTYPE_IPV6) {
      if (!pptrs->bgp_src) {
        memcpy(&pref6, &((struct ip6_hdr *)pptrs->iph_ptr)->ip6_src, sizeof(struct in6_addr));
	pptrs->bgp_src = (char *) bgp_node_match_ipv6(bgp_routing_db->rib[AFI_IP6][safi],
						      &pref6, (struct bgp_peer *) pptrs->bgp_peer);
      }
      if (!pptrs->bgp_src_info && pptrs->bgp_src) {
	result = (struct bgp_node *) pptrs->bgp_src;
        if (result->p.prefixlen >= pptrs->lm_mask_src) {
          pptrs->lm_mask_src = result->p.prefixlen;
          pptrs->lm_method_src = NF_NET_BGP;
        }

        for (info = result->info[modulo]; info; info = info->next) {
          if (safi != SAFI_MPLS_VPN) {
            if (info->peer == peer) {
              pptrs->bgp_src_info = (char *) info;
              break;
            }
          }
          else {
            if (info->peer == peer && info->extra && !memcmp(&info->extra->rd, &rd, sizeof(rd_t))) {
              pptrs->bgp_src_info = (char *) info;
              break;
            }
          }
        }
      }
      if (!pptrs->bgp_dst) {
        memcpy(&pref6, &((struct ip6_hdr *)pptrs->iph_ptr)->ip6_dst, sizeof(struct in6_addr));
	pptrs->bgp_dst = (char *) bgp_node_match_ipv6(bgp_routing_db->rib[AFI_IP6][safi],
						      &pref6, (struct bgp_peer *) pptrs->bgp_peer);
      }
      if (!pptrs->bgp_dst_info && pptrs->bgp_dst) {
	result = (struct bgp_node *) pptrs->bgp_dst; 
        if (result->p.prefixlen >= pptrs->lm_mask_dst) {
          pptrs->lm_mask_dst = result->p.prefixlen;
          pptrs->lm_method_dst = NF_NET_BGP;
        }

        for (local_modulo = modulo, modulo_idx = 0; modulo_idx < modulo_max; local_modulo++, modulo_idx++) {
          for (info = result->info[local_modulo]; info; info = info->next) {
            if (info->peer == peer) {
              int no_match = FALSE;

              /* flagging additional checks are required */
              if (safi == SAFI_MPLS_VPN) no_match++;
              if (peer->cap_add_paths) no_match++;

              if (safi == SAFI_MPLS_VPN) {
                if (info->extra && !memcmp(&info->extra->rd, &rd, sizeof(rd_t))) no_match--;
              } 

              if (peer->cap_add_paths) {
                if (info->attr) {
                  if (info->attr->mp_nexthop.family == peer_dst_ip.family) {
                    if (!memcmp(&info->attr->mp_nexthop, &peer_dst_ip, HostAddrSz)) no_match--;
                  }
                }
              }

              if (!no_match) {
	        pptrs->bgp_dst_info = (char *) info;
	        break;
	      }
	    }
          }

          /* if having results, let's not potentially look in other buckets */
          if (pptrs->bgp_dst_info) break;
        }
      }
    }
#endif

    if (follow_default && safi != SAFI_MPLS_VPN) {
      default_node = NULL;

      if (pptrs->l3_proto == ETHERTYPE_IP) {
        memset(&default_prefix, 0, sizeof(default_prefix));
        default_prefix.family = AF_INET;

        result = (struct bgp_node *) pptrs->bgp_src;
        if (result && prefix_match(&result->p, &default_prefix)) {
	  default_node = result;
	  pptrs->bgp_src = NULL;
	  pptrs->bgp_src_info = NULL;
        }

        result = (struct bgp_node *) pptrs->bgp_dst;
        if (result && prefix_match(&result->p, &default_prefix)) {
	  default_node = result;
	  pptrs->bgp_dst = NULL;
	  pptrs->bgp_dst_info = NULL;
        }
      }
#if defined ENABLE_IPV6
      else if (pptrs->l3_proto == ETHERTYPE_IPV6) {
        memset(&default_prefix, 0, sizeof(default_prefix));
        default_prefix.family = AF_INET6;

        result = (struct bgp_node *) pptrs->bgp_src;
        if (result && prefix_match(&result->p, &default_prefix)) {
          default_node = result;
          info = result->info[modulo];
          pptrs->bgp_src = NULL;
          pptrs->bgp_src_info = NULL;
        }

        result = (struct bgp_node *) pptrs->bgp_dst;
        if (result && prefix_match(&result->p, &default_prefix)) {
          default_node = result;
          info = result->info[local_modulo];
          pptrs->bgp_dst = NULL;
          pptrs->bgp_dst_info = NULL;
        }
      }
#endif
      
      if (!pptrs->bgp_src || !pptrs->bgp_dst) {
	follow_default--;
	compare_bgp_port = FALSE; // XXX: fixme: follow default in NAT traversal scenarios

        if (default_node) {
          if (info && info->attr) {
            if (info->attr->mp_nexthop.family == AF_INET) {
              sa = &sa_local;
              memset(sa, 0, sizeof(struct sockaddr));
              sa->sa_family = AF_INET;
              memcpy(&((struct sockaddr_in *)sa)->sin_addr, &info->attr->mp_nexthop.address.ipv4, 4);
	      goto start_again;
            }
#if defined ENABLE_IPV6
            else if (info->attr->mp_nexthop.family == AF_INET6) {
              sa = &sa_local;
              memset(sa, 0, sizeof(struct sockaddr));
              sa->sa_family = AF_INET6;
              ip6_addr_cpy(&((struct sockaddr_in6 *)sa)->sin6_addr, &info->attr->mp_nexthop.address.ipv6);
              goto start_again;
            }
#endif
            else {
              sa = &sa_local;
              memset(sa, 0, sizeof(struct sockaddr));
              sa->sa_family = AF_INET;
              memcpy(&((struct sockaddr_in *)sa)->sin_addr, &info->attr->nexthop, 4);
              goto start_again;
	    }
	  }
        }
      }
    }

    if (config.nfacctd_bgp_follow_nexthop[0].family && pptrs->bgp_dst && safi != SAFI_MPLS_VPN)
      bgp_follow_nexthop_lookup(pptrs);
  }
}
Ejemplo n.º 5
0
void bgp_srcdst_lookup(struct packet_ptrs *pptrs, int type)
{
  struct bgp_misc_structs *bms;
  struct bgp_rt_structs *inter_domain_routing_db;
  struct sockaddr *sa = (struct sockaddr *) pptrs->f_agent, sa_local;
  struct xflow_status_entry *xs_entry = (struct xflow_status_entry *) pptrs->f_status;
  struct bgp_peer *peer;
  struct bgp_node *default_node, *result;
  struct bgp_info *info;
  struct node_match_cmp_term2 nmct2;
  struct prefix default_prefix;
  int compare_bgp_port;
  int follow_default = config.nfacctd_bgp_follow_default;
  struct in_addr pref4;
#if defined ENABLE_IPV6
  struct in6_addr pref6;
#endif
  safi_t safi;
  rd_t rd;

  bms = bgp_select_misc_db(type);
  inter_domain_routing_db = bgp_select_routing_db(type);

  if (!bms || !inter_domain_routing_db) return;

  pptrs->bgp_src = NULL;
  pptrs->bgp_dst = NULL;
  pptrs->bgp_src_info = NULL;
  pptrs->bgp_dst_info = NULL;
  pptrs->bgp_peer = NULL;
  pptrs->bgp_nexthop_info = NULL;
  compare_bgp_port = FALSE;
  safi = SAFI_UNICAST;

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

  if (pptrs->bta || pptrs->bta2) {
    sa = &sa_local;
    if (pptrs->bta_af == ETHERTYPE_IP) {
      sa->sa_family = AF_INET;
      ((struct sockaddr_in *)sa)->sin_addr.s_addr = pptrs->bta; 
      if (pptrs->lookup_bgp_port.set) {
	((struct sockaddr_in *)sa)->sin_port = pptrs->lookup_bgp_port.n; 
	compare_bgp_port = TRUE;
      }
    }
#if defined ENABLE_IPV6
    else if (pptrs->bta_af == ETHERTYPE_IPV6) {
      sa->sa_family = AF_INET6;
      ip6_addr_32bit_cpy(&((struct sockaddr_in6 *)sa)->sin6_addr, &pptrs->bta, 0, 0, 1);
      ip6_addr_32bit_cpy(&((struct sockaddr_in6 *)sa)->sin6_addr, &pptrs->bta2, 2, 0, 1);
      if (pptrs->lookup_bgp_port.set) {
        ((struct sockaddr_in6 *)sa)->sin6_port = pptrs->lookup_bgp_port.n; 
	compare_bgp_port = TRUE;
      }
    }
#endif
  }

  start_again_follow_default:

  peer = bms->bgp_lookup_find_peer(sa, xs_entry, pptrs->l3_proto, compare_bgp_port);
  pptrs->bgp_peer = (char *) peer;

  if (peer) {
    struct host_addr peer_dst_ip;

    memset(&peer_dst_ip, 0, sizeof(peer_dst_ip));
    if (peer->cap_add_paths && (config.acct_type == ACCT_NF || config.acct_type == ACCT_SF)) {
      /* administrativia */
      struct pkt_bgp_primitives pbgp, *pbgp_ptr = &pbgp;
      memset(&pbgp, 0, sizeof(struct pkt_bgp_primitives));
      
      /* note: call to [NF|SF]_peer_dst_ip_handler for the purpose of
	 code re-use effectively is defeating the concept of libbgp */
      if (config.acct_type == ACCT_NF) NF_peer_dst_ip_handler(NULL, pptrs, (char **)&pbgp_ptr);
      else if (config.acct_type == ACCT_SF) SF_peer_dst_ip_handler(NULL, pptrs, (char **)&pbgp_ptr);

      memcpy(&peer_dst_ip, &pbgp.peer_dst_ip, sizeof(struct host_addr));
    }

    if (pptrs->bitr) {
      safi = SAFI_MPLS_VPN;
      memcpy(&rd, &pptrs->bitr, sizeof(rd));
    }

    /* XXX: can be further optimized for the case of no SAFI_UNICAST rib */
    start_again_mpls_label:

    if (pptrs->l3_proto == ETHERTYPE_IP) {
      if (!pptrs->bgp_src) {
	memset(&nmct2, 0, sizeof(struct node_match_cmp_term2));
	nmct2.peer = (struct bgp_peer *) pptrs->bgp_peer;
	nmct2.rd = &rd;
	nmct2.peer_dst_ip = NULL;

        memcpy(&pref4, &((struct pm_iphdr *)pptrs->iph_ptr)->ip_src, sizeof(struct in_addr));
	bgp_node_match_ipv4(inter_domain_routing_db->rib[AFI_IP][safi],
			    &pref4, (struct bgp_peer *) pptrs->bgp_peer,
		     	    bgp_route_info_modulo_pathid,
			    bms->bgp_lookup_node_match_cmp, &nmct2,
			    &result, &info);
      }

      if (!pptrs->bgp_src_info && result) {
        pptrs->bgp_src = (char *) result;
	pptrs->bgp_src_info = (char *) info;
        if (result->p.prefixlen >= pptrs->lm_mask_src) {
          pptrs->lm_mask_src = result->p.prefixlen;
          pptrs->lm_method_src = NF_NET_BGP;
        }
      }

      if (!pptrs->bgp_dst) {
        memset(&nmct2, 0, sizeof(struct node_match_cmp_term2));
        nmct2.peer = (struct bgp_peer *) pptrs->bgp_peer;
        nmct2.rd = &rd;
        nmct2.peer_dst_ip = &peer_dst_ip;

	memcpy(&pref4, &((struct pm_iphdr *)pptrs->iph_ptr)->ip_dst, sizeof(struct in_addr));
	bgp_node_match_ipv4(inter_domain_routing_db->rib[AFI_IP][safi],
			    &pref4, (struct bgp_peer *) pptrs->bgp_peer,
			    bgp_route_info_modulo_pathid,
			    bms->bgp_lookup_node_match_cmp, &nmct2,
			    &result, &info);
      }

      if (!pptrs->bgp_dst_info && result) {
        pptrs->bgp_dst = (char *) result;
        pptrs->bgp_dst_info = (char *) info;
        if (result->p.prefixlen >= pptrs->lm_mask_dst) {
          pptrs->lm_mask_dst = result->p.prefixlen;
          pptrs->lm_method_dst = NF_NET_BGP;
        }
      }
    }
#if defined ENABLE_IPV6
    else if (pptrs->l3_proto == ETHERTYPE_IPV6) {
      if (!pptrs->bgp_src) {
        memset(&nmct2, 0, sizeof(struct node_match_cmp_term2));
        nmct2.peer = (struct bgp_peer *) pptrs->bgp_peer;
        nmct2.rd = &rd;
        nmct2.peer_dst_ip = NULL;

        memcpy(&pref6, &((struct ip6_hdr *)pptrs->iph_ptr)->ip6_src, sizeof(struct in6_addr));
	bgp_node_match_ipv6(inter_domain_routing_db->rib[AFI_IP6][safi],
		            &pref6, (struct bgp_peer *) pptrs->bgp_peer,
		            bgp_route_info_modulo_pathid,
		            bms->bgp_lookup_node_match_cmp, &nmct2,
		            &result, &info);
      }

      if (!pptrs->bgp_src_info && result) {
        pptrs->bgp_src = (char *) result;
        pptrs->bgp_src_info = (char *) info;
        if (result->p.prefixlen >= pptrs->lm_mask_src) {
          pptrs->lm_mask_src = result->p.prefixlen;
          pptrs->lm_method_src = NF_NET_BGP;
        }
      }

      if (!pptrs->bgp_dst) {
        memset(&nmct2, 0, sizeof(struct node_match_cmp_term2));
        nmct2.peer = (struct bgp_peer *) pptrs->bgp_peer;
        nmct2.rd = &rd;
        nmct2.peer_dst_ip = &peer_dst_ip;

        memcpy(&pref6, &((struct ip6_hdr *)pptrs->iph_ptr)->ip6_dst, sizeof(struct in6_addr));
	bgp_node_match_ipv6(inter_domain_routing_db->rib[AFI_IP6][safi],
	     		    &pref6, (struct bgp_peer *) pptrs->bgp_peer,
			    bgp_route_info_modulo_pathid,
			    bms->bgp_lookup_node_match_cmp, &nmct2,
			    &result, &info);
      }

      if (!pptrs->bgp_dst_info && result) {
        pptrs->bgp_dst = (char *) result;
        pptrs->bgp_dst_info = (char *) info;
        if (result->p.prefixlen >= pptrs->lm_mask_dst) {
          pptrs->lm_mask_dst = result->p.prefixlen;
          pptrs->lm_method_dst = NF_NET_BGP;
        }
      }
    }
#endif

    if ((!pptrs->bgp_src || !pptrs->bgp_dst) && safi != SAFI_MPLS_LABEL) {
      if (pptrs->l3_proto == ETHERTYPE_IP && inter_domain_routing_db->rib[AFI_IP][SAFI_MPLS_LABEL]) {
        safi = SAFI_MPLS_LABEL;
        goto start_again_mpls_label;
      }
#if defined ENABLE_IPV6
      else if (pptrs->l3_proto == ETHERTYPE_IPV6 && inter_domain_routing_db->rib[AFI_IP6][SAFI_MPLS_LABEL]) {
        safi = SAFI_MPLS_LABEL;
        goto start_again_mpls_label;
      }
#endif
    }

    if (follow_default && safi != SAFI_MPLS_VPN) {
      default_node = NULL;

      if (pptrs->l3_proto == ETHERTYPE_IP) {
        memset(&default_prefix, 0, sizeof(default_prefix));
        default_prefix.family = AF_INET;

        result = (struct bgp_node *) pptrs->bgp_src;
        if (result && prefix_match(&result->p, &default_prefix)) {
	  default_node = result;
	  pptrs->bgp_src = NULL;
	  pptrs->bgp_src_info = NULL;
        }

        result = (struct bgp_node *) pptrs->bgp_dst;
        if (result && prefix_match(&result->p, &default_prefix)) {
	  default_node = result;
	  pptrs->bgp_dst = NULL;
	  pptrs->bgp_dst_info = NULL;
        }
      }
#if defined ENABLE_IPV6
      else if (pptrs->l3_proto == ETHERTYPE_IPV6) {
        memset(&default_prefix, 0, sizeof(default_prefix));
        default_prefix.family = AF_INET6;

        result = (struct bgp_node *) pptrs->bgp_src;
        if (result && prefix_match(&result->p, &default_prefix)) {
          default_node = result;
          pptrs->bgp_src = NULL;
          pptrs->bgp_src_info = NULL;
        }

        result = (struct bgp_node *) pptrs->bgp_dst;
        if (result && prefix_match(&result->p, &default_prefix)) {
          default_node = result;
          pptrs->bgp_dst = NULL;
          pptrs->bgp_dst_info = NULL;
        }
      }
#endif
      
      if (!pptrs->bgp_src || !pptrs->bgp_dst) {
	follow_default--;
	compare_bgp_port = FALSE; // XXX: fixme: follow default in NAT traversal scenarios

        if (default_node) {
          if (info && info->attr) {
            if (info->attr->mp_nexthop.family == AF_INET) {
              sa = &sa_local;
              memset(sa, 0, sizeof(struct sockaddr));
              sa->sa_family = AF_INET;
              memcpy(&((struct sockaddr_in *)sa)->sin_addr, &info->attr->mp_nexthop.address.ipv4, 4);
	      goto start_again_follow_default;
            }
#if defined ENABLE_IPV6
            else if (info->attr->mp_nexthop.family == AF_INET6) {
              sa = &sa_local;
              memset(sa, 0, sizeof(struct sockaddr));
              sa->sa_family = AF_INET6;
              ip6_addr_cpy(&((struct sockaddr_in6 *)sa)->sin6_addr, &info->attr->mp_nexthop.address.ipv6);
              goto start_again_follow_default;
            }
#endif
            else {
              sa = &sa_local;
              memset(sa, 0, sizeof(struct sockaddr));
              sa->sa_family = AF_INET;
              memcpy(&((struct sockaddr_in *)sa)->sin_addr, &info->attr->nexthop, 4);
              goto start_again_follow_default;
	    }
	  }
        }
      }
    }

    if (config.nfacctd_bgp_follow_nexthop[0].family && pptrs->bgp_dst && safi != SAFI_MPLS_VPN)
      bgp_follow_nexthop_lookup(pptrs, type);
  }
}
Ejemplo n.º 6
0
void bgp_follow_nexthop_lookup(struct packet_ptrs *pptrs, int type)
{
  struct bgp_misc_structs *bms;
  struct bgp_rt_structs *inter_domain_routing_db;
  struct sockaddr *sa = (struct sockaddr *) pptrs->f_agent, sa_local;
  struct bgp_peer *nh_peer;
  struct bgp_node *result_node = NULL;
  struct bgp_info *info;
  struct node_match_cmp_term2 nmct2;
  char *saved_info = NULL;
  int peers_idx, ttl = MAX_HOPS_FOLLOW_NH, self = MAX_NH_SELF_REFERENCES;
  int nh_idx, matched = 0;
  struct prefix nh, ch;
  struct in_addr pref4;
#if defined ENABLE_IPV6
  struct in6_addr pref6;
#endif
  char *saved_agent = pptrs->f_agent;
  pm_id_t bta;
  u_int32_t modulo, local_modulo, modulo_idx, modulo_max;

  bms = bgp_select_misc_db(type);
  inter_domain_routing_db = bgp_select_routing_db(type);

  if (!bms || !inter_domain_routing_db) return;

  start_again:

  if (config.nfacctd_bgp_to_agent_map && (*find_id_func)) {
    bta = 0;
    (*find_id_func)((struct id_table *)pptrs->bta_table, pptrs, &bta, NULL);
    if (bta) {
      sa = &sa_local;
      sa->sa_family = AF_INET;
      ((struct sockaddr_in *)sa)->sin_addr.s_addr = bta;
    }
  }

  for (nh_peer = NULL, peers_idx = 0; peers_idx < bms->max_peers; peers_idx++) {
    if (!sa_addr_cmp(sa, &peers[peers_idx].addr) || !sa_addr_cmp(sa, &peers[peers_idx].id)) {
      nh_peer = &peers[peers_idx];
      break;
    }
  }

  if (nh_peer) {
    modulo = bms->route_info_modulo(nh_peer, NULL, bms->table_per_peer_buckets);

    // XXX: to be optimized 
    if (bms->table_per_peer_hash == BGP_ASPATH_HASH_PATHID) modulo_max = bms->table_per_peer_buckets;
    else modulo_max = 1;

    memset(&ch, 0, sizeof(ch));
    ch.family = AF_INET;
    ch.prefixlen = 32;
    memcpy(&ch.u.prefix4, &nh_peer->addr.address.ipv4, 4);

    if (!result_node) {
      struct host_addr peer_dst_ip;
      rd_t rd;

      /* XXX: SAFI_MPLS_LABEL, SAFI_MPLS_VPN and peer_dst_ip (add_paths capability) not supported */
      memset(&peer_dst_ip, 0, sizeof(peer_dst_ip));
      memset(&rd, 0, sizeof(rd));
      memset(&nmct2, 0, sizeof(struct node_match_cmp_term2));

      nmct2.peer = (struct bgp_peer *) nh_peer;
      nmct2.rd = &rd;
      nmct2.peer_dst_ip = &peer_dst_ip;

      if (pptrs->l3_proto == ETHERTYPE_IP) {
        memcpy(&pref4, &((struct pm_iphdr *)pptrs->iph_ptr)->ip_dst, sizeof(struct in_addr));
        bgp_node_match_ipv4(inter_domain_routing_db->rib[AFI_IP][SAFI_UNICAST], &pref4, nh_peer,
			    bgp_route_info_modulo_pathid,
			    bms->bgp_lookup_node_match_cmp, &nmct2,
			    &result_node, &info);
      }
#if defined ENABLE_IPV6
      else if (pptrs->l3_proto == ETHERTYPE_IPV6) {
        memcpy(&pref6, &((struct ip6_hdr *)pptrs->iph_ptr)->ip6_dst, sizeof(struct in6_addr));
        bgp_node_match_ipv6(inter_domain_routing_db->rib[AFI_IP6][SAFI_UNICAST], &pref6, nh_peer,
			    bgp_route_info_modulo_pathid,
			    bms->bgp_lookup_node_match_cmp, &nmct2,
			    &result_node, &info);
      }
#endif
    }

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

    // XXX: to be optimized
    if (result_node) {
      for (local_modulo = modulo, modulo_idx = 0; modulo_idx < modulo_max; local_modulo++, modulo_idx++) {
        for (info = result_node->info[modulo]; info; info = info->next) {
          if (info->peer == nh_peer) break;
	}
      }
    }
    else info = NULL;

    if (info && info->attr) {
      if (info->attr->mp_nexthop.family == AF_INET) {
	nh.family = AF_INET;
	nh.prefixlen = 32;
	memcpy(&nh.u.prefix4, &info->attr->mp_nexthop.address.ipv4, 4);

	for (nh_idx = 0; config.nfacctd_bgp_follow_nexthop[nh_idx].family && nh_idx < FOLLOW_BGP_NH_ENTRIES; nh_idx++) {
	  matched = prefix_match(&config.nfacctd_bgp_follow_nexthop[nh_idx], &nh);
	  if (matched) break;
	}

	if (matched && self > 0 && ttl > 0) { 
	  if (prefix_match(&ch, &nh)) self--;
          sa = &sa_local;
          pptrs->f_agent = (char *) &sa_local;
          memset(sa, 0, sizeof(struct sockaddr));
          sa->sa_family = AF_INET;
          memcpy(&((struct sockaddr_in *)sa)->sin_addr, &info->attr->mp_nexthop.address.ipv4, 4);
	  saved_info = (char *) info;
	  ttl--;
          goto start_again;
        }
	else {
	  if (config.nfacctd_bgp_follow_nexthop_external) saved_info = (char *) info;
	  goto end;
	}
      }
#if defined ENABLE_IPV6
      else if (info->attr->mp_nexthop.family == AF_INET6) {
	nh.family = AF_INET6;
	nh.prefixlen = 128;
	memcpy(&nh.u.prefix6, &info->attr->mp_nexthop.address.ipv6, 16);

        for (nh_idx = 0; config.nfacctd_bgp_follow_nexthop[nh_idx].family && nh_idx < FOLLOW_BGP_NH_ENTRIES; nh_idx++) {
          matched = prefix_match(&config.nfacctd_bgp_follow_nexthop[nh_idx], &nh);
          if (matched) break;
        }

	if (matched && self > 0 && ttl > 0) {
	  if (prefix_match(&ch, &nh)) self--;
          sa = &sa_local;
          pptrs->f_agent = (char *) &sa_local;
          memset(sa, 0, sizeof(struct sockaddr));
          sa->sa_family = AF_INET6;
          ip6_addr_cpy(&((struct sockaddr_in6 *)sa)->sin6_addr, &info->attr->mp_nexthop.address.ipv6);
	  saved_info = (char *) info;
	  ttl--;
          goto start_again;
	}
	else {
	  if (config.nfacctd_bgp_follow_nexthop_external) saved_info = (char *) info;
	  goto end;
	}
      }
#endif
      else {
	nh.family = AF_INET;
	nh.prefixlen = 32;
	memcpy(&nh.u.prefix4, &info->attr->nexthop, 4);

        for (nh_idx = 0; config.nfacctd_bgp_follow_nexthop[nh_idx].family && nh_idx < FOLLOW_BGP_NH_ENTRIES; nh_idx++) {
          matched = prefix_match(&config.nfacctd_bgp_follow_nexthop[nh_idx], &nh);
          if (matched) break;
        }

	if (matched && self > 0 && ttl > 0) {
	  if (prefix_match(&ch, &nh)) self--;
          sa = &sa_local;
          pptrs->f_agent = (char *) &sa_local;
          memset(sa, 0, sizeof(struct sockaddr));
          sa->sa_family = AF_INET;
          memcpy(&((struct sockaddr_in *)sa)->sin_addr, &info->attr->nexthop, 4);
	  saved_info = (char *) info;
	  ttl--;
          goto start_again;
	}
	else {
	  if (config.nfacctd_bgp_follow_nexthop_external) saved_info = (char *) info;
	  goto end;
	}
      }
    }
  }

  end:

  if (saved_info) pptrs->bgp_nexthop_info = saved_info; 
  pptrs->f_agent = saved_agent;
}