19cd2d7a5SSteven/*
29cd2d7a5SSteven * Copyright (c) 2017 Cisco and/or its affiliates.
39cd2d7a5SSteven * Licensed under the Apache License, Version 2.0 (the "License");
49cd2d7a5SSteven * you may not use this file except in compliance with the License.
59cd2d7a5SSteven * You may obtain a copy of the License at:
69cd2d7a5SSteven *
79cd2d7a5SSteven *     http://www.apache.org/licenses/LICENSE-2.0
89cd2d7a5SSteven *
99cd2d7a5SSteven * Unless required by applicable law or agreed to in writing, software
109cd2d7a5SSteven * distributed under the License is distributed on an "AS IS" BASIS,
119cd2d7a5SSteven * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
129cd2d7a5SSteven * See the License for the specific language governing permissions and
139cd2d7a5SSteven * limitations under the License.
149cd2d7a5SSteven */
159cd2d7a5SSteven
169cd2d7a5SSteven#define _GNU_SOURCE
179cd2d7a5SSteven#include <vnet/bonding/node.h>
189cd2d7a5SSteven#include <vnet/ethernet/packet.h>
199cd2d7a5SSteven#include <lacp/node.h>
209cd2d7a5SSteven
219cd2d7a5SStevenlacp_state_struct lacp_state_array[] = {
229cd2d7a5SSteven#define _(b, s, n) {.bit = b, .str = #s, },
239cd2d7a5SSteven  foreach_lacp_state_flag
249cd2d7a5SSteven#undef _
259cd2d7a5SSteven  {.str = NULL}
269cd2d7a5SSteven};
279cd2d7a5SSteven
289cd2d7a5SSteven/** \file
299cd2d7a5SSteven
309cd2d7a5SSteven    2 x LACP graph nodes: an "interior" node to process
319cd2d7a5SSteven    incoming announcements, and a "process" node to periodically
329cd2d7a5SSteven    send announcements.
339cd2d7a5SSteven
349cd2d7a5SSteven    The interior node is neither pipelined nor dual-looped, because
359cd2d7a5SSteven    it would be very unusual to see more than one LACP packet in
369cd2d7a5SSteven    a given input frame. So, it's a very simple / straighforward
379cd2d7a5SSteven    example.
389cd2d7a5SSteven*/
399cd2d7a5SSteven
409cd2d7a5SSteven/*
419cd2d7a5SSteven * packet counter strings
429cd2d7a5SSteven * Dump these counters via the "show error" CLI command
439cd2d7a5SSteven */
449cd2d7a5SStevenstatic char *lacp_error_strings[] = {
459cd2d7a5SSteven#define _(sym,string) string,
469cd2d7a5SSteven  foreach_lacp_error
479cd2d7a5SSteven#undef _
489cd2d7a5SSteven};
499cd2d7a5SSteven
509cd2d7a5SSteven/*
519cd2d7a5SSteven * We actually send all lacp pkts to the "error" node after scanning
529cd2d7a5SSteven * them, so the graph node has only one next-index. The "error-drop"
539cd2d7a5SSteven * node automatically bumps our per-node packet counters for us.
549cd2d7a5SSteven */
559cd2d7a5SSteventypedef enum
569cd2d7a5SSteven{
579cd2d7a5SSteven  LACP_INPUT_NEXT_NORMAL,
589cd2d7a5SSteven  LACP_INPUT_N_NEXT,
599cd2d7a5SSteven} lacp_next_t;
609cd2d7a5SSteven
619cd2d7a5SSteven/*
629cd2d7a5SSteven * Process a frame of lacp packets
639cd2d7a5SSteven * Expect 1 packet / frame
649cd2d7a5SSteven */
659cd2d7a5SStevenstatic uword
669cd2d7a5SStevenlacp_node_fn (vlib_main_t * vm,
679cd2d7a5SSteven	      vlib_node_runtime_t * node, vlib_frame_t * frame)
689cd2d7a5SSteven{
699cd2d7a5SSteven  u32 n_left_from, *from;
709cd2d7a5SSteven  lacp_input_trace_t *t0;
719cd2d7a5SSteven
729cd2d7a5SSteven  from = vlib_frame_vector_args (frame);	/* array of buffer indices */
739cd2d7a5SSteven  n_left_from = frame->n_vectors;	/* number of buffer indices */
749cd2d7a5SSteven
759cd2d7a5SSteven  while (n_left_from > 0)
769cd2d7a5SSteven    {
779cd2d7a5SSteven      u32 bi0;
789cd2d7a5SSteven      vlib_buffer_t *b0;
799cd2d7a5SSteven      u32 next0, error0;
809cd2d7a5SSteven
819cd2d7a5SSteven      bi0 = from[0];
829cd2d7a5SSteven      b0 = vlib_get_buffer (vm, bi0);
839cd2d7a5SSteven
849cd2d7a5SSteven      next0 = LACP_INPUT_NEXT_NORMAL;
859cd2d7a5SSteven
869cd2d7a5SSteven      /* scan this lacp pkt. error0 is the counter index to bump */
879cd2d7a5SSteven      error0 = lacp_input (vm, b0, bi0);
889cd2d7a5SSteven      b0->error = node->errors[error0];
899cd2d7a5SSteven
909cd2d7a5SSteven      /* If this pkt is traced, snapshoot the data */
91977c1decSSteven Luong      if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
929cd2d7a5SSteven	{
939cd2d7a5SSteven	  int len;
94977c1decSSteven Luong
959cd2d7a5SSteven	  t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
969cd2d7a5SSteven	  len = (b0->current_length < sizeof (t0->pkt))
979cd2d7a5SSteven	    ? b0->current_length : sizeof (t0->pkt);
989cd2d7a5SSteven	  t0->len = len;
99b2ffc697SSteven	  t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
100178cf493SDave Barach	  clib_memcpy_fast (&t0->pkt, vlib_buffer_get_current (b0), len);
1019cd2d7a5SSteven	}
1029cd2d7a5SSteven      /* push this pkt to the next graph node, always error-drop */
1039cd2d7a5SSteven      vlib_set_next_frame_buffer (vm, node, next0, bi0);
1049cd2d7a5SSteven
1059cd2d7a5SSteven      from += 1;
1069cd2d7a5SSteven      n_left_from -= 1;
1079cd2d7a5SSteven    }
1089cd2d7a5SSteven
1099cd2d7a5SSteven  return frame->n_vectors;
1109cd2d7a5SSteven}
1119cd2d7a5SSteven
1129cd2d7a5SSteven/*
1139cd2d7a5SSteven * lacp input graph node declaration
1149cd2d7a5SSteven */
1159cd2d7a5SSteven/* *INDENT-OFF* */
1169cd2d7a5SStevenVLIB_REGISTER_NODE (lacp_input_node, static) = {
1179cd2d7a5SSteven  .function = lacp_node_fn,
1189cd2d7a5SSteven  .name = "lacp-input",
1199cd2d7a5SSteven  .vector_size = sizeof (u32),
1209cd2d7a5SSteven  .type = VLIB_NODE_TYPE_INTERNAL,
1219cd2d7a5SSteven
1229cd2d7a5SSteven  .n_errors = LACP_N_ERROR,
1239cd2d7a5SSteven  .error_strings = lacp_error_strings,
1249cd2d7a5SSteven
1259cd2d7a5SSteven  .format_trace = lacp_input_format_trace,
1269cd2d7a5SSteven
1279cd2d7a5SSteven  .n_next_nodes = LACP_INPUT_N_NEXT,
1289cd2d7a5SSteven  .next_nodes = {
1299cd2d7a5SSteven    [LACP_INPUT_NEXT_NORMAL] = "error-drop",
1309cd2d7a5SSteven  },
1319cd2d7a5SSteven};
1329cd2d7a5SSteven/* *INDENT-ON* */
1339cd2d7a5SSteven
1344168c4d9SSteven Luongstatic void
1354168c4d9SSteven Luonglacp_elog_start_event (void)
1364168c4d9SSteven Luong{
1374168c4d9SSteven Luong  lacp_main_t *lm = &lacp_main;
1384168c4d9SSteven Luong  /* *INDENT-OFF* */
1394168c4d9SSteven Luong  ELOG_TYPE_DECLARE (e) =
1404168c4d9SSteven Luong    {
1414168c4d9SSteven Luong      .format = "Starting LACP process, interface count = %d",
1424168c4d9SSteven Luong      .format_args = "i4",
1434168c4d9SSteven Luong    };
1444168c4d9SSteven Luong  /* *INDENT-ON* */
1454168c4d9SSteven Luong  struct
1464168c4d9SSteven Luong  {
1474168c4d9SSteven Luong    u32 count;
1484168c4d9SSteven Luong  } *ed;
1494168c4d9SSteven Luong
1504168c4d9SSteven Luong  ed = ELOG_DATA (&vlib_global_main.elog_main, e);
1514168c4d9SSteven Luong  ed->count = lm->lacp_int;
1524168c4d9SSteven Luong}
1534168c4d9SSteven Luong
1544168c4d9SSteven Luongstatic void
1554168c4d9SSteven Luonglacp_elog_stop_event (void)
1564168c4d9SSteven Luong{
1574168c4d9SSteven Luong  lacp_main_t *lm = &lacp_main;
1584168c4d9SSteven Luong  /* *INDENT-OFF* */
1594168c4d9SSteven Luong  ELOG_TYPE_DECLARE (e) =
1604168c4d9SSteven Luong    {
1614168c4d9SSteven Luong      .format = "Stopping LACP process, interface count = %d",
1624168c4d9SSteven Luong      .format_args = "i4",
1634168c4d9SSteven Luong    };
1644168c4d9SSteven Luong  /* *INDENT-ON* */
1654168c4d9SSteven Luong  struct
1664168c4d9SSteven Luong  {
1674168c4d9SSteven Luong    u32 count;
1684168c4d9SSteven Luong  } *ed;
1694168c4d9SSteven Luong
1704168c4d9SSteven Luong  ed = ELOG_DATA (&vlib_global_main.elog_main, e);
1714168c4d9SSteven Luong  ed->count = lm->lacp_int;
1724168c4d9SSteven Luong}
1734168c4d9SSteven Luong
1749cd2d7a5SSteven/*
1759cd2d7a5SSteven * lacp periodic function
1769cd2d7a5SSteven */
1779cd2d7a5SStevenstatic uword
1789cd2d7a5SStevenlacp_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
1799cd2d7a5SSteven{
1809cd2d7a5SSteven  lacp_main_t *lm = &lacp_main;
1819cd2d7a5SSteven  f64 poll_time_remaining;
1829cd2d7a5SSteven  uword event_type, *event_data = 0;
1839cd2d7a5SSteven
1849cd2d7a5SSteven  ethernet_register_input_type (vm, ETHERNET_TYPE_SLOW_PROTOCOLS /* LACP */ ,
1859cd2d7a5SSteven				lacp_input_node.index);
1869cd2d7a5SSteven
1879cd2d7a5SSteven  poll_time_remaining = 0.2;
1889cd2d7a5SSteven  while (1)
1899cd2d7a5SSteven    {
1904168c4d9SSteven Luong      if (lm->lacp_int > 0)
1919cd2d7a5SSteven	poll_time_remaining =
1929cd2d7a5SSteven	  vlib_process_wait_for_event_or_clock (vm, poll_time_remaining);
1939cd2d7a5SSteven      else
1949cd2d7a5SSteven	vlib_process_wait_for_event (vm);
1959cd2d7a5SSteven
1969cd2d7a5SSteven      event_type = vlib_process_get_events (vm, &event_data);
1979cd2d7a5SSteven      switch (event_type)
1989cd2d7a5SSteven	{
1999cd2d7a5SSteven	case ~0:		/* no events => timeout */
2009cd2d7a5SSteven	  break;
2019cd2d7a5SSteven	case LACP_PROCESS_EVENT_START:
2024168c4d9SSteven Luong	  poll_time_remaining = 0.2;
2034168c4d9SSteven Luong	  lacp_elog_start_event ();
2049cd2d7a5SSteven	  break;
2059cd2d7a5SSteven	case LACP_PROCESS_EVENT_STOP:
2064168c4d9SSteven Luong	  if (lm->lacp_int == 0)
2074168c4d9SSteven Luong	    {
2084168c4d9SSteven Luong	      poll_time_remaining = SECS_IN_A_DAY;
2094168c4d9SSteven Luong	      lacp_elog_stop_event ();
2104168c4d9SSteven Luong	    }
2114168c4d9SSteven Luong	  break;
2129cd2d7a5SSteven	default:
2139cd2d7a5SSteven	  clib_warning ("BUG: event type 0x%wx", event_type);
2149cd2d7a5SSteven	  break;
2159cd2d7a5SSteven	}
2164168c4d9SSteven Luong      vec_reset_length (event_data);
2179cd2d7a5SSteven
2189cd2d7a5SSteven      if (vlib_process_suspend_time_is_zero (poll_time_remaining))
2199cd2d7a5SSteven	{
2209cd2d7a5SSteven	  lacp_periodic (vm);
2219cd2d7a5SSteven	  poll_time_remaining = 0.2;
2229cd2d7a5SSteven	}
2239cd2d7a5SSteven    }
2249cd2d7a5SSteven
2259cd2d7a5SSteven  return 0;
2269cd2d7a5SSteven}
2279cd2d7a5SSteven
2284168c4d9SSteven Luongvoid
2294168c4d9SSteven Luonglacp_create_periodic_process (void)
2304168c4d9SSteven Luong{
2314168c4d9SSteven Luong  lacp_main_t *lm = &lacp_main;
2324168c4d9SSteven Luong
2334168c4d9SSteven Luong  /* Already created the process node? */
2344168c4d9SSteven Luong  if (lm->lacp_process_node_index > 0)
2354168c4d9SSteven Luong    return;
2364168c4d9SSteven Luong
2374168c4d9SSteven Luong  /* No, create it now and make a note of the node index */
2384168c4d9SSteven Luong  lm->lacp_process_node_index =
2394168c4d9SSteven Luong    vlib_process_create (lm->vlib_main, "lacp-process", lacp_process,
2404168c4d9SSteven Luong			 16 /* log2_n_stack_bytes */ );
2414168c4d9SSteven Luong}
2429cd2d7a5SSteven
2439cd2d7a5SSteven/*
2449cd2d7a5SSteven * fd.io coding-style-patch-verification: ON
2459cd2d7a5SSteven *
2469cd2d7a5SSteven * Local Variables:
2479cd2d7a5SSteven * eval: (c-set-style "gnu")
2489cd2d7a5SSteven * End:
2499cd2d7a5SSteven */
250