summaryrefslogtreecommitdiffstats
path: root/src/plugins/igmp
AgeCommit message (Expand)AuthorFilesLines
2018-08-27IGMP: enable command on cliNeale Ranns4-2/+84
2018-08-27cmake: Fix plugins .h includesMohsin Kazmi1-0/+4
2018-08-25cmake: improve add_vpp_plugin macroDamjan Marion1-2/+5
2018-08-17CMake as an alternative to autotools (experimental)Damjan Marion1-0/+29
2018-07-12IGMP: validate the packets length in the DPNeale Ranns3-25/+55
2018-07-10IGMP: coverity found defectsNeale Ranns3-4/+10
2018-07-09IGMP improvementsNeale Ranns27-1734/+3760
2018-06-29igmp: bugfix and minor improvementsJakub Grajciar5-76/+60
2018-06-10IGMP: use simple u32 bit hash keyNeale Ranns3-18/+15
2018-06-08Add reaper functions to want events APIs (VPP-1304)Neale Ranns2-32/+43
2018-05-23VPP-1283: IPv4 PMTU missing MTU value in ICMP4 message.Ole Troan1-1/+1
2018-04-25igmp: disable debug messagesDamjan Marion1-1/+1
2018-04-25igmp: data structure refactoringJakub Grajciar5-350/+820
2018-04-17igmp: fix debug macroJakub Grajciar3-13/+13
2018-03-23IGMP: coverity fixes and remove checks for scapy IGMPv3Neale Ranns2-9/+5
2018-03-21IGMP plugin initialises the FIB/MFIB via ip4 moduleNeale Ranns1-1/+4
2018-03-19IGMP pluginJakub Grajciar12-0/+2720
342'>342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
/*
 *------------------------------------------------------------------
 * svmtool.c
 *
 * Copyright (c) 2009 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *------------------------------------------------------------------
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#include <fcntl.h>
#include <string.h>
#include <vppinfra/clib.h>
#include <vppinfra/vec.h>
#include <vppinfra/hash.h>
#include <vppinfra/bitmap.h>
#include <vppinfra/fifo.h>
#include <vppinfra/time.h>
#include <vppinfra/mheap.h>
#include <vppinfra/heap.h>
#include <vppinfra/pool.h>
#include <vppinfra/format.h>

#include "svm.h"



/*
 * format_all_svm_regions
 * Maps / unmaps regions. Do NOT call from client code!
 */
u8 *
format_all_svm_regions (u8 * s, va_list * args)
{
  int verbose = va_arg (*args, int);
  svm_region_t *root_rp = svm_get_root_rp ();
  svm_main_region_t *mp;
  svm_subregion_t *subp;
  svm_region_t *rp;
  svm_map_region_args_t *a = 0;
  u8 **svm_names = 0;
  u8 *name = 0;
  int i;

  ASSERT (root_rp);

  pthread_mutex_lock (&root_rp->mutex);

  s = format (s, "%U", format_svm_region, root_rp, verbose);

  mp = root_rp->data_base;

  /*
   * Snapshoot names, can't hold root rp mutex across
   * find_or_create.
   */
  /* *INDENT-OFF* */
  pool_foreach (subp, mp->subregions, ({
        name = vec_dup (subp->subregion_name);
        vec_add1(svm_names, name);
      }));
  /* *INDENT-ON* */

  pthread_mutex_unlock (&root_rp->mutex);

  for (i = 0; i < vec_len (svm_names); i++)
    {
      vec_validate (a, 0);
      a->name = (char *) svm_names[i];
      rp = svm_region_find_or_create (a);
      if (rp)
	{
	  pthread_mutex_lock (&rp->mutex);
	  s = format (s, "%U", format_svm_region, rp, verbose);
	  pthread_mutex_unlock (&rp->mutex);
	  svm_region_unmap (rp);
	  vec_free (svm_names[i]);
	}
      vec_free (a);
    }
  vec_free (svm_names);
  return (s);
}

void
show (char *chroot_path, int verbose)
{
  svm_map_region_args_t *a = 0;

  vec_validate (a, 0);

  svm_region_init_chroot (chroot_path);

  fformat (stdout, "My pid is %d\n", getpid ());

  fformat (stdout, "%U", format_all_svm_regions, verbose);

  svm_region_exit ();

  vec_free (a);
}


static void *
svm_map_region_nolock (svm_map_region_args_t * a)
{
  int svm_fd;
  svm_region_t *rp;
  int deadman = 0;
  u8 *shm_name;

  ASSERT ((a->size & ~(MMAP_PAGESIZE - 1)) == a->size);

  shm_name = shm_name_from_svm_map_region_args (a);

  svm_fd = shm_open ((char *) shm_name, O_RDWR, 0777);

  if (svm_fd < 0)
    {
      perror ("svm_region_map(mmap open)");
      return (0);
    }
  vec_free (shm_name);

  rp = mmap (0, MMAP_PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, svm_fd, 0);

  if (rp == (svm_region_t *) MAP_FAILED)
    {
      close (svm_fd);
      clib_warning ("mmap");
      return (0);
    }
  /*
   * We lost the footrace to create this region; make sure
   * the winner has crossed the finish line.
   */
  while (rp->version == 0 && deadman++ < 5)
    {
      sleep (1);
    }

  /*
   * <bleep>-ed?
   */
  if (rp->version == 0)
    {
      clib_warning ("rp->version %d not %d", rp->version, SVM_VERSION);
      munmap (rp, MMAP_PAGESIZE);
      return (0);
    }
  /* Remap now that the region has been placed */
  a->baseva = rp->virtual_base;
  a->size = rp->virtual_size;
  munmap (rp, MMAP_PAGESIZE);

  rp = (void *) mmap (uword_to_pointer (a->baseva, void *), a->size,
		      PROT_READ | PROT_WRITE,
		      MAP_SHARED | MAP_FIXED, svm_fd, 0);
  if ((uword) rp == (uword) MAP_FAILED)
    {
      clib_unix_warning ("mmap");
      return (0);
    }

  if ((uword) rp != rp->virtual_base)
    {
      clib_warning ("mmap botch");
    }

  if (pthread_mutex_trylock (&rp->mutex))
    {
      clib_warning ("rp->mutex LOCKED by pid %d, tag %d, cleared...",
		    rp->mutex_owner_pid, rp->mutex_owner_tag);
      clib_memset (&rp->mutex, 0, sizeof (rp->mutex));

    }
  else
    {
      clib_warning ("mutex OK...\n");
      pthread_mutex_unlock (&rp->mutex);
    }

  return ((void *) rp);
}

/*
 * rnd_pagesize
 * Round to a pagesize multiple, presumably 4k works
 */
static u64
rnd_pagesize (u64 size)
{
  u64 rv;

  rv = (size + (MMAP_PAGESIZE - 1)) & ~(MMAP_PAGESIZE - 1);
  return (rv);
}

#define MUTEX_DEBUG

always_inline void
region_lock (svm_region_t * rp, int tag)
{
  pthread_mutex_lock (&rp->mutex);
#ifdef MUTEX_DEBUG
  rp->mutex_owner_pid = getpid ();
  rp->mutex_owner_tag = tag;
#endif
}

always_inline void
region_unlock (svm_region_t * rp)
{
#ifdef MUTEX_DEBUG
  rp->mutex_owner_pid = 0;
  rp->mutex_owner_tag = 0;
#endif
  pthread_mutex_unlock (&rp->mutex);
}


static void *
svm_existing_region_map_nolock (void *root_arg, svm_map_region_args_t * a)
{
  svm_region_t *root_rp = root_arg;
  svm_main_region_t *mp;
  svm_region_t *rp;
  void *oldheap;
  uword *p;

  a->size += MMAP_PAGESIZE +
    (a->pvt_heap_size ? a->pvt_heap_size : SVM_PVT_MHEAP_SIZE);
  a->size = rnd_pagesize (a->size);

  region_lock (root_rp, 4);
  oldheap = svm_push_pvt_heap (root_rp);
  mp = root_rp->data_base;

  ASSERT (mp);

  p = hash_get_mem (mp->name_hash, a->name);

  if (p)
    {
      rp = svm_map_region_nolock (a);
      region_unlock (root_rp);
      svm_pop_heap (oldheap);
      return rp;
    }
  return 0;

}

static void
trace (char *chroot_path, char *name, int enable_disable)
{
  svm_map_region_args_t *a = 0;
  svm_region_t *db_rp;
  void *oldheap;

  vec_validate (a, 0);

  svm_region_init_chroot (chroot_path);

  a->name = name;
  a->size = 1 << 20;
  a->flags = SVM_FLAGS_MHEAP;

  db_rp = svm_region_find_or_create (a);

  ASSERT (db_rp);

  region_lock (db_rp, 20);

  oldheap = svm_push_data_heap (db_rp);

  mheap_trace (db_rp->data_heap, enable_disable);

  svm_pop_heap (oldheap);
  region_unlock (db_rp);

  svm_region_unmap ((void *) db_rp);
  svm_region_exit ();
  vec_free (a);
}



static void
subregion_repair (char *chroot_path)
{
  int i;
  svm_main_region_t *mp;
  svm_map_region_args_t a;
  svm_region_t *root_rp;
  svm_region_t *rp;
  svm_subregion_t *subp;
  u8 *name = 0;
  u8 **svm_names = 0;

  svm_region_init_chroot (chroot_path);
  root_rp = svm_get_root_rp ();

  pthread_mutex_lock (&root_rp->mutex);

  mp = root_rp->data_base;

  /*
   * Snapshoot names, can't hold root rp mutex across
   * find_or_create.
   */
  /* *INDENT-OFF* */
  pool_foreach (subp, mp->subregions, ({
        name = vec_dup (subp->subregion_name);
        vec_add1(svm_names, name);
      }));
  /* *INDENT-ON* */

  pthread_mutex_unlock (&root_rp->mutex);

  for (i = 0; i < vec_len (svm_names); i++)
    {
      clib_memset (&a, 0, sizeof (a));
      a.root_path = chroot_path;
      a.name = (char *) svm_names[i];
      fformat (stdout, "Checking %s region...\n", a.name);
      rp = svm_existing_region_map_nolock (root_rp, &a);
      if (rp)
	{
	  svm_region_unmap (rp);
	  vec_free (svm_names[i]);
	}
    }
  vec_free (svm_names);
}

void
repair (char *chroot_path, int crash_root_region)
{
  svm_region_t *root_rp = 0;
  svm_map_region_args_t *a = 0;
  void *svm_map_region (svm_map_region_args_t * a);
  int svm_fd;
  u8 *shm_name;

  fformat (stdout, "our pid: %d\n", getpid ());

  vec_validate (a, 0);

  a->root_path = chroot_path;
  a->name = SVM_GLOBAL_REGION_NAME;
  a->baseva = svm_get_global_region_base_va ();
  a->size = SVM_GLOBAL_REGION_SIZE;
  a->flags = SVM_FLAGS_NODATA;

  shm_name = shm_name_from_svm_map_region_args (a);

  svm_fd = shm_open ((char *) shm_name, O_RDWR, 0777);

  if (svm_fd < 0)
    {
      perror ("svm_region_map(mmap open)");
      goto out;
    }

  vec_free (shm_name);

  root_rp = mmap (0, MMAP_PAGESIZE,
		  PROT_READ | PROT_WRITE, MAP_SHARED, svm_fd, 0);

  if (root_rp == (svm_region_t *) MAP_FAILED)
    {
      close (svm_fd);
      clib_warning ("mmap");
      goto out;
    }

  /* Remap now that the region has been placed */
  clib_warning ("remap to 0x%x", root_rp->virtual_base);

  a->baseva = root_rp->virtual_base;
  a->size = root_rp->virtual_size;
  munmap (root_rp, MMAP_PAGESIZE);

  root_rp = (void *) mmap (uword_to_pointer (a->baseva, void *), a->size,
			   PROT_READ | PROT_WRITE,
			   MAP_SHARED | MAP_FIXED, svm_fd, 0);
  if ((uword) root_rp == (uword) MAP_FAILED)
    {
      clib_unix_warning ("mmap");
      goto out;
    }

  close (svm_fd);

  if ((uword) root_rp != root_rp->virtual_base)
    {
      clib_warning ("mmap botch");
      goto out;
    }

  if (pthread_mutex_trylock (&root_rp->mutex))
    {
      clib_warning ("root_rp->mutex LOCKED by pid %d, tag %d, cleared...",
		    root_rp->mutex_owner_pid, root_rp->mutex_owner_tag);
      clib_memset (&root_rp->mutex, 0, sizeof (root_rp->mutex));
      goto out;
    }
  else
    {
      clib_warning ("root_rp->mutex OK...\n");
      pthread_mutex_unlock (&root_rp->mutex);
    }

out:
  vec_free (a);
  /*
   * Now that the root region is known to be OK,
   * fix broken subregions
   */
  subregion_repair (chroot_path);

  if (crash_root_region)
    {
      clib_warning ("Leaving root region locked on purpose...");
      pthread_mutex_lock (&root_rp->mutex);
      root_rp->mutex_owner_pid = getpid ();
      root_rp->mutex_owner_tag = 99;
    }
  svm_region_exit ();
}

int
main (int argc, char **argv)
{
  unformat_input_t input;
  int parsed = 0;
  char *name;
  char *chroot_path = 0;
  u8 *chroot_u8;

  unformat_init_command_line (&input, argv);

  while (unformat_check_input (&input) != UNFORMAT_END_OF_INPUT)
    {
      if (unformat (&input, "show-verbose"))
	{
	  show (chroot_path, 1);
	  parsed++;
	}
      else if (unformat (&input, "show"))
	{
	  show (chroot_path, 0);
	  parsed++;
	}
      else if (unformat (&input, "client-scan"))
	{
	  svm_client_scan (chroot_path);
	  parsed++;
	}
      else if (unformat (&input, "repair"))
	{
	  repair (chroot_path, 0 /* fix it */ );
	  parsed++;
	}
      else if (unformat (&input, "crash"))
	{
	  repair (chroot_path, 1 /* crash it */ );
	  parsed++;
	}
      else if (unformat (&input, "trace-on %s", &name))
	{
	  trace (chroot_path, name, 1);
	  parsed++;
	}
      else if (unformat (&input, "trace-off %s", &name))
	{
	  trace (chroot_path, name, 0);
	  parsed++;
	}
      else if (unformat (&input, "chroot %s", &chroot_u8))
	{
	  chroot_path = (char *) chroot_u8;
	}
      else
	{
	  break;
	}
    }

  unformat_free (&input);

  if (!parsed)
    {
      fformat (stdout,
	       "%s: show | show-verbose | client-scan | trace-on <region-name>\n",
	       argv[0]);
      fformat (stdout, "      trace-off <region-name>\n");
    }
  exit (0);
}

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */