aboutsummaryrefslogtreecommitdiffstats
path: root/hicn-plugin/src/strategy_node.c
blob: 31585077f4dd7acb9793d5e3e743b43f6b061298 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* 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
/*
 * Copyright (c) 2021-2022 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 <vlib/vlib.h>
#include <vnet/vnet.h>

#include "hicn.h"
#include "parser.h"
#include "strategy.h"
#include "strategy_dpo_ctx.h"
#include "infra.h"
#include "mgmt.h"
#include "pcs.h"
#include "state.h"
#include "data_fwd.h"
#include "strategies/strategy_mw.h"

/* Registration struct for a graph node */
vlib_node_registration_t hicn_strategy_node;

/*
 * Node context data (to be used in all the strategy nodes); we think this is
 * per-thread/instance
 */
typedef struct hicn_strategy_runtime_s
{
  int id;
  hicn_pit_cs_t *pitcs;
} hicn_strategy_runtime_t;

/* Stats string values */
static char *hicn_strategy_error_strings[] = {
#define _(sym, string) string,
  foreach_hicnfwd_error
#undef _
};

/* packet trace format function */
u8 *
hicn_strategy_format_trace (u8 *s, va_list *args)
{
  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
  hicn_strategy_trace_t *t = va_arg (*args, hicn_strategy_trace_t *);

  const hicn_strategy_vft_t *vft = hicn_dpo_get_strategy_vft (t->dpo_type);

  return vft->hicn_format_strategy_trace (s, t);
}

always_inline void
drop_packet (vlib_main_t *vm, u32 bi0, u32 *n_left_to_next, u32 *next0,
	     u32 **to_next, u32 *next_index, vlib_node_runtime_t *node)
{
  *next0 = HICN_STRATEGY_NEXT_ERROR_DROP;

  (*to_next)[0] = bi0;
  *to_next += 1;
  *n_left_to_next -= 1;

  vlib_validate_buffer_enqueue_x1 (vm, node, *next_index, *to_next,
				   *n_left_to_next, bi0, *next0);
}

/*
 * ICN strategy later node for interests: - 1 packet at a time - ipv4/tcp
 * ipv6/tcp
 */
uword
hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
		  vlib_frame_t *frame)
{

  int ret;
  u32 n_left_from, *from, *to_next, n_left_to_next;
  hicn_strategy_next_t next_index;
  hicn_strategy_runtime_t *rt = NULL;
  vl_api_hicn_api_node_stats_get_reply_t stats = { 0 };
  f64 tnow;
  vlib_buffer_t *b0;
  u32 bi0;
  hicn_face_id_t outfaces[MAX_OUT_FACES];
  u32 clones[MAX_OUT_FACES];
  u16 outfaces_len;
  u32 next0;
  const hicn_dpo_ctx_t *dpo_ctx;
  const hicn_strategy_vft_t *strategy;
  hicn_buffer_t *hicnb0;
  hicn_pcs_entry_t *pcs_entry = NULL;

  from = vlib_frame_vector_args (frame);
  n_left_from = frame->n_vectors;
  next_index = (hicn_strategy_next_t) node->cached_next_index;
  rt = vlib_node_get_runtime_data (vm, hicn_strategy_node.index);
  rt->pitcs = &hicn_main.pitcs;
  /* Capture time in vpp terms */
  tnow = vlib_time_now (vm);
  next0 = next_index;

  while (n_left_from > 0)
    {

      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
      while (n_left_from > 0 && n_left_to_next > 0)
	{
	  // Prefetch for next iteration
	  if (n_left_from > 1)
	    {
	      vlib_buffer_t *b1;
	      b1 = vlib_get_buffer (vm, from[1]);
	      CLIB_PREFETCH (b1, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
	    }

	  // Dequeue a packet buffer
	  bi0 = from[0];
	  from += 1;
	  n_left_from -= 1;
	  b0 = vlib_get_buffer (vm, bi0);

	  // Drop by default
	  next0 = HICN_STRATEGY_NEXT_ERROR_DROP;

	  // Increment counters
	  stats.pkts_processed++;

	  hicnb0 = hicn_get_buffer (b0);

	  // Get the strategy VFT
	  hicnb0->dpo_ctx_id = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
	  dpo_ctx = hicn_strategy_dpo_ctx_get (hicnb0->dpo_ctx_id);
	  hicnb0->vft_id = dpo_ctx->dpo_type;
	  strategy = hicn_dpo_get_strategy_vft (hicnb0->vft_id);
	  strategy->hicn_add_interest (hicnb0->dpo_ctx_id);

	  // Check we have at least one next hop for the packet
	  ret = strategy->hicn_select_next_hop (hicnb0->dpo_ctx_id, outfaces,
						&outfaces_len);

	  if (PREDICT_FALSE (ret != HICN_ERROR_NONE || outfaces_len == 0))
	    {
	      drop_packet (vm, bi0, &n_left_from, &next0, &to_next,
			   &next_index, node);
	      continue;
	    }

	  // Create a new PIT entry
	  pcs_entry = hicn_pcs_entry_pit_get (rt->pitcs, tnow,
					      hicn_buffer_get_lifetime (b0));

	  // Add entry to PIT table
	  hicn_name_t name;
	  hicn_packet_get_name (&hicnb0->pkbuf, &name);
	  ret = hicn_pcs_pit_insert (rt->pitcs, pcs_entry, &name);

	  if (PREDICT_FALSE (ret != HICN_ERROR_NONE))
	    {
	      drop_packet (vm, bi0, &n_left_from, &next0, &to_next,
			   &next_index, node);
	      continue;
	    }

	  // Store internal state
	  ret = hicn_store_internal_state (
	    b0, hicn_pcs_entry_get_index (rt->pitcs, pcs_entry),
	    vnet_buffer (b0)->ip.adj_index[VLIB_TX]);

	  if (PREDICT_FALSE (ret != HICN_ERROR_NONE))
	    {
	      hicn_pcs_entry_remove_lock (rt->pitcs, pcs_entry);
	      drop_packet (vm, bi0, &n_left_from, &next0, &to_next,
			   &next_index, node);
	      continue;
	    }

	  // Add face
	  hicn_pcs_entry_pit_add_face (pcs_entry, hicnb0->face_id);

	  // Set next node
	  next0 = hicn_buffer_is_v6 (b0) ? HICN_STRATEGY_NEXT_INTEREST_FACE6 :
						 HICN_STRATEGY_NEXT_INTEREST_FACE4;

	  if (PREDICT_TRUE (ret == HICN_ERROR_NONE))
	    {
	      // Clone interest if needed
	      if (outfaces_len > 1)
		{
		  ret = vlib_buffer_clone (vm, bi0, clones, (u16) outfaces_len,
					   CLIB_CACHE_LINE_BYTES * 2);
		  ASSERT (ret == outfaces_len);
		}
	      else
		{
		  clones[0] = bi0;
		}

	      // Send interest to next hops
	      for (u32 nh = 0; nh < outfaces_len; nh++)
		{
		  vlib_buffer_t *local_b0 = vlib_get_buffer (vm, clones[nh]);

		  to_next[0] = clones[nh];
		  to_next += 1;
		  n_left_to_next -= 1;

		  vnet_buffer (local_b0)->ip.adj_index[VLIB_TX] = outfaces[nh];
		  stats.pkts_interest_count++;

		  // Maybe trace
		  if (PREDICT_FALSE (
			(node->flags & VLIB_NODE_FLAG_TRACE) &&
			(local_b0->flags & VLIB_BUFFER_IS_TRACED)))
		    {
		      hicn_strategy_trace_t *t =
			vlib_add_trace (vm, node, local_b0, sizeof (*t));
		      t->pkt_type = HICN_PACKET_TYPE_DATA;
		      t->sw_if_index =
			vnet_buffer (local_b0)->sw_if_index[VLIB_RX];
		      t->next_index = next0;
		      t->dpo_type = hicnb0->vft_id;
		    }

		  /*
		   * Fix in case of a wrong speculation. Needed for
		   * cloning the data in the right frame
		   */
		  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
						   to_next, n_left_to_next,
						   clones[nh], next0);
		}
	    }
	  else
	    {
	      drop_packet (vm, bi0, &n_left_from, &next0, &to_next,
			   &next_index, node);
	    }
	}

      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    }

  vlib_node_increment_counter (vm, hicn_strategy_node.index,
			       HICNFWD_ERROR_PROCESSED, stats.pkts_processed);
  vlib_node_increment_counter (vm, hicn_strategy_node.index,
			       HICNFWD_ERROR_INTERESTS,
			       stats.pkts_interest_count);

  return (frame->n_vectors);
}

/*
 * Node registration for the forwarder node
 */
VLIB_REGISTER_NODE (hicn_strategy_node) =
  {
   .name = "hicn-strategy",
   .function = hicn_strategy_fn,
   .vector_size = sizeof (u32),
   .runtime_data_bytes = sizeof (int) + sizeof(hicn_pit_cs_t *),
   .format_trace = hicn_strategy_format_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
   .n_errors = ARRAY_LEN (hicn_strategy_error_strings),
   .error_strings = hicn_strategy_error_strings,
   .n_next_nodes = HICN_STRATEGY_N_NEXT,
   .next_nodes =
   {
    [HICN_STRATEGY_NEXT_INTEREST_HITPIT] = "hicn-interest-hitpit",
    [HICN_STRATEGY_NEXT_INTEREST_HITCS] = "hicn-interest-hitcs",
    [HICN_STRATEGY_NEXT_INTEREST_FACE4] = "hicn4-face-output",
    [HICN_STRATEGY_NEXT_INTEREST_FACE6] = "hicn6-face-output",
    [HICN_STRATEGY_NEXT_ERROR_DROP] = "error-drop",
   },
  };

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