summaryrefslogtreecommitdiffstats
path: root/src/vcl/vcl_private.h
AgeCommit message (Collapse)AuthorFilesLines
2018-09-14vcl: keep track of unexpected eventsFlorin Coras1-0/+3
If sessions are marked as blocking, events for other sessions received while waiting for the blocking sessions, are added to a pending list and processed later. Change-Id: Ia6c71006b1c2bcb78af708390da0cd436af397cc Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-09-12vcl: add apis that expos fifo as bufferFlorin Coras1-0/+1
Change-Id: I4bd9c9f73499711e04b38d53daa5c917a4285bf5 Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-09-08vcl: set worker pthread stop keyFlorin Coras1-0/+3
Otherwise the key destructor is not called on pthread_exit. Change-Id: I11e6b9683a926eecd3f40a44aab41924ff9c3101 Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-09-08vcl: register workers in orderFlorin Coras1-0/+3
Change-Id: Ibc74e7f7587f8b17fc0dcec20cc4530b9dd4c3ca Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-09-06session: support multiple worker bindsFlorin Coras1-1/+1
Allows app workers to listen on the same session endpoint. Incoming connects are spread across the workers in a round-robin fashion Change-Id: Ib5f5817230d9abc6127a85cdbdcad70d980c0f7f Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-08-30vcl: add support for multi-worker appsFlorin Coras1-76/+166
Add basic support for app registration of multiple workers. LDP does not work with multi-worker apps. Change-Id: I3fc421a2a591a077b275827463f874b261415a63 Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-08-28vcl: remove session locksFlorin Coras1-50/+0
Support for multi-worker apps will be added in future patches. This also disables vce. Change-Id: I43b0ed2d5daa2b3d8f8a12fb18bd89dcdfa0619d Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-08-10vcl: support for eventfd mq signalingFlorin Coras1-1/+62
- support eventfd based mq signaling. Based on configuration, vcl epoll/select can use either condvars or epoll on mq eventfds. - add vcl support for memfd segments - vpp explicitly registers cut-through segments with apps/vcl - if using eventfd, make ldp allow one call to libc_epoll_create. Needed for the message queue epfd - update svm_queue_t to allow blocking calls with eventfd signaling. Change-Id: I064151ac370bbe29bb16c968bf4e3659c8286bea Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-07-31vcl: add read/write udp supportFlorin Coras1-0/+9
Change-Id: Ie6171c12055cde6915856de340839f5da1b1b1da Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-07-27vcl: use events for epoll/select/read/writeFlorin Coras1-1/+61
Have vcl poll and wait on the event message queues as opposed to constantly polling the session fifos. This also adds event signaling to cut through sessions. On the downside, because we can't wait on multiple condvars, i.e., when we have multiple message queues because of cut-through registrations, we do timed waits. Change-Id: I29ade95dba449659fe46008bb1af502276a7c5fd Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-07-17session: use msg queue for eventsFlorin Coras1-1/+1
Change-Id: I3c58367eec2243fe19b75be78a175c5261863e9e Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-06-28vcl: move binary api and cfg to separate filesFlorin Coras1-0/+337
Change-Id: Ib88d703bb7d4b170059960b0688352c90c5fcc39 Signed-off-by: Florin Coras <fcoras@cisco.com>
Name.Tag */ .highlight .nv { color: #f8f8f2 } /* Name.Variable */ .highlight .ow { color: #f92672 } /* Operator.Word */ .highlight .w { color: #f8f8f2 } /* Text.Whitespace */ .highlight .mb { color: #ae81ff } /* Literal.Number.Bin */ .highlight .mf { color: #ae81ff } /* Literal.Number.Float */ .highlight .mh { color: #ae81ff } /* Literal.Number.Hex */ .highlight .mi { color: #ae81ff } /* Literal.Number.Integer */ .highlight .mo { color: #ae81ff } /* Literal.Number.Oct */ .highlight .sa { color: #e6db74 } /* Literal.String.Affix */ .highlight .sb { color: #e6db74 } /* Literal.String.Backtick */ .highlight .sc { color: #e6db74 } /* Literal.String.Char */ .highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */ .highlight .sd { color: #e6db74 } /* Literal.String.Doc */ .highlight .s2 { color: #e6db74 } /* Literal.String.Double */ .highlight .se { color: #ae81ff } /* Literal.String.Escape */ .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */ .highlight .si { color: #e6db74 } /* Literal.String.Interpol */ .highlight .sx { color: #e6db74 } /* Literal.String.Other */ .highlight .sr { color: #e6db74 } /* Literal.String.Regex */ .highlight .s1 { color: #e6db74 } /* Literal.String.Single */ .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #a6e22e } /* Name.Function.Magic */ .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ } @media (prefers-color-scheme: light) { .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .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 */ }
/*
 *------------------------------------------------------------------
 * ip_api.c - vnet ip api
 *
 * Copyright (c) 2016 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 <stddef.h>

#include <vnet/ip-neighbor/ip_neighbor.h>
#include <vnet/ip-neighbor/ip_neighbor_watch.h>
#include <vnet/ip/ip_types_api.h>
#include <vnet/ethernet/ethernet_types_api.h>

#include <vlibapi/api.h>
#include <vlibmemory/api.h>

#include <vnet/ip-neighbor/ip_neighbor.api_enum.h>
#include <vnet/ip-neighbor/ip_neighbor.api_types.h>

static u16 msg_id_base;
#define REPLY_MSG_ID_BASE msg_id_base

#include <vlibapi/api_helper_macros.h>

#include <vnet/format_fns.h>


static ip46_type_t
ip46_type_from_af (ip_address_family_t af)
{
  return (AF_IP4 == af ? IP46_TYPE_IP4 : IP46_TYPE_IP6);
}

static vl_api_ip_neighbor_flags_t
ip_neighbor_flags_encode (ip_neighbor_flags_t f)
{
  vl_api_ip_neighbor_flags_t v = IP_API_NEIGHBOR_FLAG_NONE;

  if (f & IP_NEIGHBOR_FLAG_STATIC)
    v |= IP_API_NEIGHBOR_FLAG_STATIC;
  if (f & IP_NEIGHBOR_FLAG_NO_FIB_ENTRY)
    v |= IP_API_NEIGHBOR_FLAG_NO_FIB_ENTRY;

  return (v);
}

static void
ip_neighbor_encode (vl_api_ip_neighbor_t * api, const ip_neighbor_t * ipn)
{
  api->sw_if_index = htonl (ipn->ipn_key->ipnk_sw_if_index);
  api->flags = ip_neighbor_flags_encode (ipn->ipn_flags);

  ip_address_encode (&ipn->ipn_key->ipnk_ip,
		     ipn->ipn_key->ipnk_type, &api->ip_address);
  mac_address_encode (&ipn->ipn_mac, api->mac_address);
}

void
ip_neighbor_handle_event (const ip_neighbor_event_t * ipne)
{
  vl_api_ip_neighbor_event_t *mp;
  vl_api_registration_t *reg;
  const ip_neighbor_t *ipn;

  ipn = ip_neighbor_get (ipne->ipne_index);

  if (NULL == ipn)
    /* Client can cancel, die, etc. */
    return;

  /* Customer(s) requesting event for this neighbor */
  reg = vl_api_client_index_to_registration (ipne->ipne_watch.ipw_client);
  if (!reg)
    return;

  if (vl_api_can_send_msg (reg))
    {
      mp = vl_msg_api_alloc (sizeof (*mp));
      clib_memset (mp, 0, sizeof (*mp));
      mp->_vl_msg_id = ntohs (VL_API_IP_NEIGHBOR_EVENT + REPLY_MSG_ID_BASE);
      mp->client_index = ipne->ipne_watch.ipw_client;
      mp->pid = ipne->ipne_watch.ipw_pid;

      ip_neighbor_encode (&mp->neighbor, ipn);

      vl_api_send_msg (reg, (u8 *) mp);
    }
  else
    {
      static f64 last_time;
      /*
       * Throttle syslog msgs.
       * It's pretty tempting to just revoke the registration...
       */
      if (vlib_time_now (vlib_get_main ()) > last_time + 10.0)
	{
	  clib_warning ("ip6 nd event for %U to pid %d: queue stuffed!",
			format_ip46_address, &ipn->ipn_key->ipnk_ip,
			IP46_TYPE_ANY, ipne->ipne_watch.ipw_pid);
	  last_time = vlib_time_now (vlib_get_main ());
	}
    }
}

typedef struct ip_neighbor_dump_ctx_t_
{
  vl_api_registration_t *reg;
  u32 context;
} ip_neighbor_dump_ctx_t;

static walk_rc_t
send_ip_neighbor_details (index_t ipni, void *arg)
{
  ip_neighbor_dump_ctx_t *ctx = arg;
  vl_api_ip_neighbor_details_t *mp;
  ip_neighbor_t *ipn;

  ipn = ip_neighbor_get (ipni);
  mp = vl_msg_api_alloc (sizeof (*mp));
  clib_memset (mp, 0, sizeof (*mp));
  mp->_vl_msg_id = ntohs (VL_API_IP_NEIGHBOR_DETAILS + REPLY_MSG_ID_BASE);
  mp->context = ctx->context;
  mp->age =
    clib_host_to_net_f64 ((vlib_time_now (vlib_get_main ()) -
			   ipn->ipn_time_last_updated));
  ip_neighbor_encode (&mp->neighbor, ipn);

  vl_api_send_msg (ctx->reg, (u8 *) mp);

  return (WALK_CONTINUE);
}

static void
vl_api_ip_neighbor_dump_t_handler (vl_api_ip_neighbor_dump_t * mp)
{
  vl_api_registration_t *reg;
  ip_address_family_t af;
  int rv;

  reg = vl_api_client_index_to_registration (mp->client_index);
  if (!reg)
    return;

  u32 sw_if_index = ntohl (mp->sw_if_index);

  rv = ip_address_family_decode (mp->af, &af);

  if (rv)
    return;

  ip_neighbor_dump_ctx_t ctx = {
    .reg = reg,
    .context = mp->context,
  };

  // walk all neighbours on all interfaces
  ip_neighbor_walk ((af == AF_IP4 ?
		     IP46_TYPE_IP4 :
		     IP46_TYPE_IP6),
		    sw_if_index, send_ip_neighbor_details, &ctx);
}

static ip_neighbor_flags_t
ip_neighbor_flags_decode (vl_api_ip_neighbor_flags_t v)
{
  ip_neighbor_flags_t f = IP_NEIGHBOR_FLAG_NONE;

  if (v & IP_API_NEIGHBOR_FLAG_STATIC)
    f |= IP_NEIGHBOR_FLAG_STATIC;
  if (v & IP_API_NEIGHBOR_FLAG_NO_FIB_ENTRY)
    f |= IP_NEIGHBOR_FLAG_NO_FIB_ENTRY;

  return (f);
}

static void
vl_api_ip_neighbor_add_del_t_handler (vl_api_ip_neighbor_add_del_t * mp,
				      vlib_main_t * vm)
{
  vl_api_ip_neighbor_add_del_reply_t *rmp;
  ip_neighbor_flags_t flags;
  u32 stats_index = ~0;
  ip46_address_t ip = ip46_address_initializer;
  mac_address_t mac;
  ip46_type_t type;
  int rv;

  VALIDATE_SW_IF_INDEX ((&mp->neighbor));

  flags = ip_neighbor_flags_decode (mp->neighbor.flags);
  type = ip_address_decode (&mp->neighbor.ip_address, &ip);
  mac_address_decode (mp->neighbor.mac_address, &mac);

  /* must be static or dynamic, default to dynamic */
  if (!(flags & IP_NEIGHBOR_FLAG_STATIC) &&
      !(flags & IP_NEIGHBOR_FLAG_DYNAMIC))
    flags |= IP_NEIGHBOR_FLAG_DYNAMIC;

  /*
   * there's no validation here of the ND/ARP entry being added.
   * The expectation is that the FIB will ensure that nothing bad
   * will come of adding bogus entries.
   */
  if (mp->is_add)
    rv = ip_neighbor_add (&ip, type, &mac,
			  ntohl (mp->neighbor.sw_if_index),
			  flags, &stats_index);
  else
    rv = ip_neighbor_del (&ip, type, ntohl (mp->neighbor.sw_if_index));

  BAD_SW_IF_INDEX_LABEL;

  /* *INDENT-OFF* */
  REPLY_MACRO2 (VL_API_IP_NEIGHBOR_ADD_DEL_REPLY,
  ({
    rmp->stats_index = htonl (stats_index);
  }));
  /* *INDENT-ON* */
}

static void
vl_api_want_ip_neighbor_events_t_handler (vl_api_want_ip_neighbor_events_t *
					  mp)
{
  vl_api_want_ip_neighbor_events_reply_t *rmp;
  ip46_address_t ip;
  ip46_type_t itype;
  int rv = 0;

  if (mp->sw_if_index != ~0)
    VALIDATE_SW_IF_INDEX (mp);
  itype = ip_address_decode (&mp->ip, &ip);

  ip_neighbor_watcher_t watch = {
    .ipw_client = mp->client_index,
    .ipw_pid = mp->pid,
  };

  if (mp->enable)
    ip_neighbor_watch (&ip, itype, ntohl (mp->sw_if_index), &watch);
  else
    ip_neighbor_unwatch (&ip, itype, ntohl (mp->sw_if_index), &watch);

  BAD_SW_IF_INDEX_LABEL;
  REPLY_MACRO (VL_API_WANT_IP_NEIGHBOR_EVENTS_REPLY);
}

static void
vl_api_ip_neighbor_config_t_handler (vl_api_ip_neighbor_config_t * mp)
{
  vl_api_ip_neighbor_config_reply_t *rmp;
  ip_address_family_t af;
  int rv;

  rv = ip_address_family_decode (mp->af, &af);

  if (!rv)
    rv = ip_neighbor_config (ip46_type_from_af (af),
			     ntohl (mp->max_number),
			     ntohl (mp->max_age), mp->recycle);

  REPLY_MACRO (VL_API_IP_NEIGHBOR_CONFIG_REPLY);
}

#define vl_msg_name_crc_list
#include <vnet/ip-neighbor/ip_neighbor.api.h>
#undef vl_msg_name_crc_list

#include <vnet/ip-neighbor/ip_neighbor.api.c>

static clib_error_t *
ip_neighbor_api_init (vlib_main_t * vm)
{
  /* Ask for a correctly-sized block of API message decode slots */
  msg_id_base = setup_message_id_table ();

  return 0;
}

VLIB_API_INIT_FUNCTION (ip_neighbor_api_init);

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