Exemplo n.º 1
0
void update_slots_used(squeue *q, uint32_t *bitmap, struct netmap_ring *ring) {
  struct msg_transaction_update_data *msg_data;
  uint16_t i;
  uint32_t *mask;
  size_t bitmap_blocks_per_data_block;

  bitmap_blocks_per_data_block = (MSG_BLOCKSIZE * CHAR_BIT) / BITMAP_BLOCKSIZE;
  mask = bitmap_new(ring->num_slots);
  assert(mask);

  // reconsitute the mask
  for (i=0; i < BITMAP_BLOCKS(ring->num_slots); i++) {
    if (i % bitmap_blocks_per_data_block == 0) {
      msg_data = squeue_get_next_pop_slot(q);
      assert(msg_data);
    }
    mask[i] = msg_data->data[i%bitmap_blocks_per_data_block];
  }

  bitmap_clearmask(bitmap, ring->num_slots, mask, ring->num_slots);

  // reduce the range of slots in use as indicated by the bitmap
  while (!bitmap_get(bitmap,
            (ring->num_slots + ring->cur - ring->reserved) % ring->num_slots)) {
    ring->reserved--;
    if (!ring->reserved)
      break;
  }
}
Exemplo n.º 2
0
int main() {
  squeue *q;
  int rc = 0;
  int i;
  int *p;
  size_t n;
  int d;

  q = squeue_new(1024, 4);
  if (!q) {
    printf("squeue_new failed\n");
    exit(EXIT_FAILURE);
  }

  uint32_t data[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
  rc = squeue_enter(q, 1);
  if (rc) {
    for (p = squeue_get_next_push_slot(q), i=0; 
          p; 
          p = squeue_get_next_push_slot(q), i=(i+1)%10) {
      *p = data[i];
    }
    squeue_exit(q);
  }

  rc = squeue_enter(q, 1);
  if (rc) {
    for (p = squeue_get_next_pop_slot(q); p; p = squeue_get_next_pop_slot(q)) {
      printf("%u ", *p);
    }
    squeue_exit(q);
  }
  printf("\n********************\n");

  do {
    n = squeue_push_many(q, data, 1, 10); 
  } while (n == 10); 

  for (n = squeue_pop(q, &d, 1); n > 0; n = squeue_pop(q, &d, 0)) {
    printf("%u ", d);
  }
  printf("\n********************\n");

  exit(EXIT_SUCCESS);
}
Exemplo n.º 3
0
void* squeue_trypop_slot(squeue *q) {
  int rc;

  assert(q);
  rc = pthread_mutex_trylock(&q->lock);
  if(rc != 0)
    return NULL;

  return squeue_get_next_pop_slot(q);
}
Exemplo n.º 4
0
void *dispatcher(void *threadarg) {
  assert(threadarg);

  struct thread_context *context;
  struct thread_context *contexts;
  int rv;
  struct netmap_ring *rxring;
  struct ethernet_pkt *etherpkt;
  struct pollfd pfd;
  struct dispatcher_data *data;
  uint32_t *slots_used, *open_transactions;
  uint32_t i, arpd_idx, num_threads;
  char *buf;
  struct msg_hdr *msg;
  struct ether_addr *mac;

  context = (struct thread_context *)threadarg;
  contexts = context->shared->contexts;
  data = context->data;
  arpd_idx = context->shared->arpd_idx;
  mac = &context->shared->if_info->mac;
  num_threads = context->shared->num_threads;

  struct transaction *transactions[num_threads];
  uint64_t dropped[num_threads];
  for (i=0; i < num_threads; i++) {
    transactions[i] = NULL;
    dropped[i] = 0;
  }

  rv = dispatcher_init(context);
  if (!rv) {
    pthread_exit(NULL);
  }

  rxring = NETMAP_RXRING(data->nifp, 0);
  slots_used = bitmap_new(rxring->num_slots);
  if (!slots_used)
    pthread_exit(NULL);

  open_transactions = bitmap_new(num_threads);
  if (!open_transactions)
    pthread_exit(NULL);

  pfd.fd = data->fd;
  pfd.events = (POLLIN);

  printf("dispatcher[%d]: initialized\n", context->thread_id);
  // signal to main() that we are initialized
  atomic_store_explicit(&context->initialized, 1, memory_order_release);

  for (;;) {
    rv = poll(&pfd, 1, POLL_TIMEOUT);

    // read all packets from the ring
    if (rv > 0) {
      for (; rxring->avail > 0; rxring->avail--) {
        i = rxring->cur;
        rxring->cur = NETMAP_RING_NEXT(rxring, i);
        rxring->reserved++;
        buf = NETMAP_BUF(rxring, rxring->slot[i].buf_idx);
        etherpkt = (struct ethernet_pkt *)(void *)buf;

        // TODO: consider pushing this check to the workers
        if (!ethernet_is_valid(etherpkt, mac)) {
          if (rxring->reserved == 1)
            rxring->reserved = 0;
          continue;
        }

        // TODO: dispatch to n workers instead of just 0
        switch (etherpkt->h.ether_type) {
          case IP4_ETHERTYPE:
            rv = tqueue_insert(contexts[0].pkt_recv_q,
                               &transactions[0], (char *) NULL + i);
            switch (rv) {
              case TQUEUE_SUCCESS:
                bitmap_set(slots_used, i);
                bitmap_set(open_transactions, 0);
                break;
              case TQUEUE_TRANSACTION_FULL:
                bitmap_set(slots_used, i);
                bitmap_clear(open_transactions, 0);
                break;
              case TQUEUE_FULL:
                // just drop packet and do accounting
                dropped[0]++;
                if (rxring->reserved == 1)
                  rxring->reserved = 0;
                break;
            }
            break;
          case ARP_ETHERTYPE:
            rv = tqueue_insert(contexts[arpd_idx].pkt_recv_q,
                               &transactions[arpd_idx], (char *) NULL + i);
            switch (rv) {
              case TQUEUE_SUCCESS:
                tqueue_publish_transaction(contexts[arpd_idx].pkt_recv_q,
                                            &transactions[arpd_idx]);
                bitmap_set(slots_used, i);
                break;
              case TQUEUE_TRANSACTION_FULL:
                bitmap_set(slots_used, i);
                break;
              case TQUEUE_FULL:
                // just drop packet and do accounting
                dropped[arpd_idx]++;
                if (rxring->reserved == 1)
                  rxring->reserved = 0;
                break;
            }
            break;
          default:
            printf("dispatcher[%d]: unknown/unsupported ethertype %hu\n",
                    context->thread_id, etherpkt->h.ether_type);
            if (rxring->reserved == 1)
              rxring->reserved = 0;
        } // switch (ethertype)
      } // for (rxring)

      // publish any open transactions so that the worker can start on it
      for (i=0; i < num_threads; i++) {
        if (bitmap_get(open_transactions, i))
          tqueue_publish_transaction(contexts[i].pkt_recv_q, &transactions[i]);
      }
      bitmap_clearall(open_transactions, num_threads);
    } // if (packets)

    // read the message queue
    rv = squeue_enter(context->msg_q, 1);
    if (!rv)
      continue;
    while ((msg = squeue_get_next_pop_slot(context->msg_q)) != NULL) {
      switch (msg->msg_type) {
        case MSG_TRANSACTION_UPDATE:
          update_slots_used(context->msg_q, slots_used, rxring);
          break;
        case MSG_TRANSACTION_UPDATE_SINGLE:
          update_slots_used_single((void *)msg, slots_used, rxring);
          break;
        default:
          printf("dispatcher: unknown message %hu\n", msg->msg_type);
      }
    }
    squeue_exit(context->msg_q);

  } // for(;;)

  pthread_exit(NULL);
}
Exemplo n.º 5
0
// public function definitions
void *arpd(void *threadarg) {
  assert(threadarg);

  struct thread_context *context;
  struct thread_context *contexts;
  struct arpd_data *data;
  struct in_addr *my_addr;
  int rv;

  struct transaction *transaction = NULL;
  struct ethernet_pkt *etherpkt;
  struct arp_pkt *arp;
  struct netmap_ring *rxring;
  void *ring_idx;
  uint32_t dispatcher_idx;
  struct msg_hdr *msg_hdr;

  context = (struct thread_context *)threadarg;
  contexts = context->shared->contexts;
  data = context->data;
  rxring = data->rxring;
  dispatcher_idx = context->shared->dispatcher_idx;
  my_addr = &context->shared->inet_info->addr;

  rv = arpd_init(context);
  if (!rv) {
    pthread_exit(NULL);
  }

  printf("arpd[%d]: initialized\n", context->thread_id);
  // signal to main() that we are initialized
  atomic_store_explicit(&context->initialized, 1, memory_order_release);

  // main event loop
  for (;;) {
    // read all the incoming packets
    while (tqueue_remove(context->pkt_recv_q, &transaction, 
            &ring_idx) > 0) {
      etherpkt = (struct ethernet_pkt *) NETMAP_BUF(rxring, 
                                    rxring->slot[(uint32_t)ring_idx].buf_idx);
      arp = (struct arp_pkt*) etherpkt->data;

      if (!arp_is_valid(arp)) {
        send_msg_transaction_update_single(&contexts[dispatcher_idx],
                                            (uint32_t)ring_idx);
        continue;
      }

      if (arp->arp_h.ar_op == ARP_OP_REQUEST) {
        if (arp->tpa.s_addr != my_addr->s_addr) {
          send_msg_transaction_update_single(&contexts[dispatcher_idx],
                                              (uint32_t) ring_idx);
          continue;
        }

        printf("R)");
        arp_print_line(arp);

        // send_pkt_arp_reply could fail when xmit queue is full,
        // however, the sender should just resend a request
        send_pkt_arp_reply(context->pkt_xmit_q, &arp->spa, &arp->sha);
      } else {  // ARP_OP_REPLY
        if (!arp_reply_filter(arp, my_addr)) {
          send_msg_transaction_update_single(&contexts[dispatcher_idx],
                                              (uint32_t) ring_idx);
          continue;
        }

        printf("R)");
        arp_print_line(arp);

        // TODO: also check against a list of my outstanding arp requests
        // prior to insertion in the arp cache
        recv_pkt_arp_reply(arp, data->arp_cache, contexts);
      }

      send_msg_transaction_update_single(&contexts[dispatcher_idx],
                                          (uint32_t) ring_idx);
    } // while (packets)

    // resend outstanding requests and refresh expiring entries
    update_arp_cache(data->arp_cache, contexts, context->pkt_xmit_q);

    // TODO: read all the messages
    rv = squeue_enter(context->msg_q, 1);
    if (!rv)
      continue;

    while ((msg_hdr = squeue_get_next_pop_slot(context->msg_q)) != NULL) {
      switch (msg_hdr->msg_type) {
        case MSG_ARPD_GET_MAC:
          recv_msg_get_mac((void *)msg_hdr, data->arp_cache,
                            contexts, context->pkt_xmit_q);
          break;
        default:
          printf("arpd: unknown message %hu\n", msg_hdr->msg_type);
      }
    }
    squeue_exit(context->msg_q);

    usleep(ARP_CACHE_RETRY_INTERVAL);
  } // for (;;)

  pthread_exit(NULL);
}
Exemplo n.º 6
0
// public function definitions
void *worker(void *threadarg) {
  assert(threadarg);

  struct thread_context *context;
  struct thread_context *contexts;
  struct thread_context *dispatcher;
  struct worker_data *data;
  int rv;

  struct transaction *transaction = NULL;
  struct netmap_ring *rxring;
  void *ring_idx;
  uint32_t *slots_read;
  pktbuff *pktbuff_in, *pktbuff_out;
  int pktbuff_used = 1;
  struct pcb *pcb;
  struct msg_hdr *msg_hdr;

  context = (struct thread_context *)threadarg;
  contexts = context->shared->contexts;
  data = context->data;
  dispatcher = &contexts[context->shared->dispatcher_idx];

  rxring = data->rxring;
  slots_read = bitmap_new(rxring->num_slots);
  if (!slots_read)
    pthread_exit(NULL);

  rv = worker_init(context);
  if (!rv) {
    pthread_exit(NULL);
  }

  printf("worker[%d]: initialized\n", context->thread_id);
  // signal to main() that we are initialized
  atomic_store_explicit(&context->initialized, 1, memory_order_release);

  for (;;) {
    if (pktbuff_used)
      pktbuff_out = pktbuff_allocator_borrow(&data->pktbuff_allocator);

    if (pktbuff_out) {
      pktbuff_out->thread_id = context->thread_id;
      pktbuff_used = 0;
      // read all the incoming packets
      while ((rv = tqueue_remove(context->pkt_recv_q, &transaction, &ring_idx))
                  != TQUEUE_EMPTY) {
        pktbuff_in = (void *)NETMAP_BUF(rxring,
                                     rxring->slot[(uint32_t)ring_idx].buf_idx);

        recv_pktbuff(pktbuff_in, pktbuff_out, &pcb, &pktbuff_used, context);
        if (pktbuff_used) {
          if (send_pktbuff(pktbuff_out, pcb, context, data) < 0)
            pktbuff_used = 0;
        }

        bitmap_set(slots_read, (uint32_t)ring_idx);
        if (rv == TQUEUE_TRANSACTION_EMPTY) {
          send_msg_transaction_update(dispatcher, slots_read,
                                      rxring->num_slots);
          bitmap_clearall(slots_read, rxring->num_slots);
        }
      } // while (packets)
    }   // pktbuff_out

    // read all the messages
    // TODO: handle MSG_ARPD_GET_MAC_REPLY, MSG_PACKET_SENT
    rv = squeue_enter(context->msg_q, 1);
    if (!rv)
      continue;
    while ((msg_hdr = squeue_get_next_pop_slot(context->msg_q)) != NULL) {
      switch (msg_hdr->msg_type) {
        case MSG_PACKET_SENT:
          pktbuff_allocator_return(&data->pktbuff_allocator,
                                ((struct msg_packet_sent *)msg_hdr)->pktbuff);
          break;
        case MSG_ARPD_GET_MAC_REPLY:  // for now, just ignore
          break;
        default:
          printf("worker[%d]: unknown message %hu\n", context->thread_id,
                  msg_hdr->msg_type);
      }
    }
    squeue_exit(context->msg_q);

    usleep(1000);
  } // for (;;)

  pthread_exit(NULL);
}