summaryrefslogtreecommitdiffstats
path: root/test/test_ip4_vrf_multi_instance.py
AgeCommit message (Expand)AuthorFilesLines
2020-05-03tests: vpp_interface remove deprecated packed propertiesPaul Vinciguerra1-2/+0
2019-12-17ip: Protocol Independent IP NeighborsNeale Ranns1-3/+3
2019-12-14tests: changes for scapy 2.4.3 migrationsnaramre1-2/+2
2019-11-26fib: Table ReplaceNeale Ranns1-4/+3
2019-11-05misc: Fix python scripts shebang lineRenato Botelho do Couto1-1/+1
2019-10-18ip: ip vrf tests python3 supportOle Troan1-7/+1
2019-06-18fib: fib api updatesNeale Ranns1-9/+11
2019-04-11Tests: Refactor tearDown show command logging, add lifecycle markers.Paul Vinciguerra1-3/+4
2019-04-10Tests Cleanup: Fix missing calls to setUpClass/tearDownClass.Paul Vinciguerra1-0/+4
2019-03-11VPP-1508: Use scapy.compat to manage packet level library differences.Paul Vinciguerra1-1/+3
2019-03-07Tests: Refactor payload_to_info()Paul Vinciguerra1-1/+1
2019-03-06test framework: vpp_papi_provider.py - further cleanupOle Troan1-2/+2
2018-08-08Remove unnecessary routes during vrf-multi-instances testsNeale Ranns1-3/+0
2018-06-26Add negative tests for leaking across different VRFs - ip4/6Jan Gelety1-16/+86
2018-04-13Enable check of VRF reset - IPv4Jan Gelety1-42/+64
2017-09-11FIB table add/delete APINeale Ranns1-1/+3
2017-03-03Changing the IP table for an interface is an error if the interface already h...Neale Ranns1-0/+1
2017-03-02Remove the unused VRF ID parameter from the IP neighbour Add/Del APINeale Ranns1-1/+1
2017-01-27ipv4 vrf test doc cleaningJan Gelety1-6/+6
2017-01-11make test: improve documentation and PEP8 complianceKlement Sekera1-5/+6
2017-01-11test: ip4 vrf instances multi-context test (CSIT-492)Jan1-0/+410
ion */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
/*
 * Copyright (c) 2018 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.
 */
/**
 * @file
 * @brief NAT plugin client-IP based session affinity for load-balancing
 */

#include <nat/nat_affinity.h>
#include <nat/nat.h>

nat_affinity_main_t nat_affinity_main;

#define AFFINITY_HASH_BUCKETS 65536
#define AFFINITY_HASH_MEMORY (2 << 25)

u8 *
format_affinity_kvp (u8 * s, va_list * args)
{
  clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
  nat_affinity_key_t k;

  k.as_u64[0] = v->key[0];
  k.as_u64[1] = v->key[1];

  s = format (s, "client %U backend %U:%d proto %U index %llu",
	      format_ip4_address, &k.client_addr,
	      format_ip4_address, &k.service_addr,
	      clib_net_to_host_u16 (k.service_port),
	      format_nat_protocol, k.proto);

  return s;
}

clib_error_t *
nat_affinity_init (vlib_main_t * vm)
{
  nat_affinity_main_t *nam = &nat_affinity_main;
  vlib_thread_main_t *tm = vlib_get_thread_main ();
  clib_error_t *error = 0;

  if (tm->n_vlib_mains > 1)
    clib_spinlock_init (&nam->affinity_lock);

  clib_bihash_init_16_8 (&nam->affinity_hash, "nat-affinity",
			 AFFINITY_HASH_BUCKETS, AFFINITY_HASH_MEMORY);
  clib_bihash_set_kvp_format_fn_16_8 (&nam->affinity_hash,
				      format_affinity_kvp);

  nam->vlib_main = vm;

  return error;
}

static_always_inline void
make_affinity_kv (clib_bihash_kv_16_8_t * kv, ip4_address_t client_addr,
		  ip4_address_t service_addr, u8 proto, u16 service_port)
{
  nat_affinity_key_t *key = (nat_affinity_key_t *) kv->key;

  key->client_addr = client_addr;
  key->service_addr = service_addr;
  key->proto = proto;
  key->service_port = service_port;

  kv->value = ~0ULL;
}

u32
nat_affinity_get_per_service_list_head_index (void)
{
  nat_affinity_main_t *nam = &nat_affinity_main;
  dlist_elt_t *head_elt;

  clib_spinlock_lock_if_init (&nam->affinity_lock);

  pool_get (nam->list_pool, head_elt);
  clib_dlist_init (nam->list_pool, head_elt - nam->list_pool);

  clib_spinlock_unlock_if_init (&nam->affinity_lock);

  return head_elt - nam->list_pool;
}

void
nat_affinity_flush_service (u32 affinity_per_service_list_head_index)
{
  nat_affinity_main_t *nam = &nat_affinity_main;
  u32 elt_index;
  dlist_elt_t *elt;
  nat_affinity_t *a;
  clib_bihash_kv_16_8_t kv;

  clib_spinlock_lock_if_init (&nam->affinity_lock);

  while ((elt_index =
	  clib_dlist_remove_head (nam->list_pool,
				  affinity_per_service_list_head_index)) !=
	 ~0)
    {
      elt = pool_elt_at_index (nam->list_pool, elt_index);
      a = pool_elt_at_index (nam->affinity_pool, elt->value);
      kv.key[0] = a->key.as_u64[0];
      kv.key[1] = a->key.as_u64[1];
      pool_put_index (nam->affinity_pool, elt->value);
      if (clib_bihash_add_del_16_8 (&nam->affinity_hash, &kv, 0))
	nat_elog_warn ("affinity key del failed");
      pool_put_index (nam->list_pool, elt_index);
    }
  pool_put_index (nam->list_pool, affinity_per_service_list_head_index);

  clib_spinlock_unlock_if_init (&nam->affinity_lock);
}

int
nat_affinity_find_and_lock (ip4_address_t client_addr,
			    ip4_address_t service_addr, u8 proto,
			    u16 service_port, u8 * backend_index)
{
  nat_affinity_main_t *nam = &nat_affinity_main;
  clib_bihash_kv_16_8_t kv, value;
  nat_affinity_t *a;
  int rv = 0;

  make_affinity_kv (&kv, client_addr, service_addr, proto, service_port);
  clib_spinlock_lock_if_init (&nam->affinity_lock);
  if (clib_bihash_search_16_8 (&nam->affinity_hash, &kv, &value))
    {
      rv = 1;
      goto unlock;
    }

  a = pool_elt_at_index (nam->affinity_pool, value.value);
  /* if already expired delete */
  if (a->ref_cnt == 0)
    {
      if (a->expire < vlib_time_now (nam->vlib_main))
	{
	  clib_dlist_remove (nam->list_pool, a->per_service_index);
	  pool_put_index (nam->list_pool, a->per_service_index);
	  pool_put_index (nam->affinity_pool, value.value);
	  if (clib_bihash_add_del_16_8 (&nam->affinity_hash, &kv, 0))
	    nat_elog_warn ("affinity key del failed");
	  rv = 1;
	  goto unlock;
	}
    }
  a->ref_cnt++;
  *backend_index = a->backend_index;

unlock:
  clib_spinlock_unlock_if_init (&nam->affinity_lock);
  return rv;
}

static int
affinity_is_expired_cb (clib_bihash_kv_16_8_t * kv, void *arg)
{
  nat_affinity_main_t *nam = &nat_affinity_main;
  nat_affinity_t *a;

  a = pool_elt_at_index (nam->affinity_pool, kv->value);
  if (a->ref_cnt == 0)
    {
      if (a->expire < vlib_time_now (nam->vlib_main))
	{
	  clib_dlist_remove (nam->list_pool, a->per_service_index);
	  pool_put_index (nam->list_pool, a->per_service_index);
	  pool_put_index (nam->affinity_pool, kv->value);
	  if (clib_bihash_add_del_16_8 (&nam->affinity_hash, kv, 0))
	    nat_elog_warn ("affinity key del failed");
	  return 1;
	}
    }

  return 0;
}

int
nat_affinity_create_and_lock (ip4_address_t client_addr,
			      ip4_address_t service_addr, u8 proto,
			      u16 service_port, u8 backend_index,
			      u32 sticky_time,
			      u32 affinity_per_service_list_head_index)
{
  nat_affinity_main_t *nam = &nat_affinity_main;
  clib_bihash_kv_16_8_t kv, value;
  nat_affinity_t *a;
  dlist_elt_t *list_elt;
  int rv = 0;

  make_affinity_kv (&kv, client_addr, service_addr, proto, service_port);
  clib_spinlock_lock_if_init (&nam->affinity_lock);
  if (!clib_bihash_search_16_8 (&nam->affinity_hash, &kv, &value))
    {
      rv = 1;
      nat_elog_notice ("affinity key already exist");
      goto unlock;
    }

  pool_get (nam->affinity_pool, a);
  kv.value = a - nam->affinity_pool;
  rv =
    clib_bihash_add_or_overwrite_stale_16_8 (&nam->affinity_hash, &kv,
					     affinity_is_expired_cb, NULL);
  if (rv)
    {
      nat_elog_notice ("affinity key add failed");
      pool_put (nam->affinity_pool, a);
      goto unlock;
    }

  pool_get (nam->list_pool, list_elt);
  clib_dlist_init (nam->list_pool, list_elt - nam->list_pool);
  list_elt->value = a - nam->affinity_pool;
  a->per_service_index = list_elt - nam->list_pool;
  a->backend_index = backend_index;
  a->ref_cnt = 1;
  a->sticky_time = sticky_time;
  a->key.as_u64[0] = kv.key[0];
  a->key.as_u64[1] = kv.key[1];
  clib_dlist_addtail (nam->list_pool, affinity_per_service_list_head_index,
		      a->per_service_index);

unlock:
  clib_spinlock_unlock_if_init (&nam->affinity_lock);
  return rv;
}

void
nat_affinity_unlock (ip4_address_t client_addr, ip4_address_t service_addr,
		     u8 proto, u16 service_port)
{
  nat_affinity_main_t *nam = &nat_affinity_main;
  clib_bihash_kv_16_8_t kv, value;
  nat_affinity_t *a;

  make_affinity_kv (&kv, client_addr, service_addr, proto, service_port);
  clib_spinlock_lock_if_init (&nam->affinity_lock);
  if (clib_bihash_search_16_8 (&nam->affinity_hash, &kv, &value))
    goto unlock;

  a = pool_elt_at_index (nam->affinity_pool, value.value);
  a->ref_cnt--;
  if (a->ref_cnt == 0)
    a->expire = (u64) a->sticky_time + vlib_time_now (nam->vlib_main);

unlock:
  clib_spinlock_unlock_if_init (&nam->affinity_lock);
}

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