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 <lacp/node.h>
199cd2d7a5SSteven
209cd2d7a5SStevenint
219cd2d7a5SStevenlacp_dump_ifs (lacp_interface_details_t ** out_lacpifs)
229cd2d7a5SSteven{
239cd2d7a5SSteven  vnet_main_t *vnm = vnet_get_main ();
249cd2d7a5SSteven  bond_main_t *bm = &bond_main;
259cd2d7a5SSteven  slave_if_t *sif;
269cd2d7a5SSteven  bond_if_t *bif;
279cd2d7a5SSteven  vnet_hw_interface_t *hi;
289cd2d7a5SSteven  lacp_interface_details_t *r_lacpifs = NULL;
299cd2d7a5SSteven  lacp_interface_details_t *lacpif = NULL;
309cd2d7a5SSteven
319cd2d7a5SSteven  /* *INDENT-OFF* */
329cd2d7a5SSteven  pool_foreach (sif, bm->neighbors,
33bac326cbSSteven Luong    if (sif->lacp_enabled == 0)
349cd2d7a5SSteven      continue;
359cd2d7a5SSteven    vec_add2(r_lacpifs, lacpif, 1);
36b7b92993SDave Barach    clib_memset (lacpif, 0, sizeof (*lacpif));
379cd2d7a5SSteven    lacpif->sw_if_index = sif->sw_if_index;
389cd2d7a5SSteven    hi = vnet_get_hw_interface (vnm, sif->hw_if_index);
399cd2d7a5SSteven    clib_memcpy(lacpif->interface_name, hi->name,
409cd2d7a5SSteven                MIN (ARRAY_LEN (lacpif->interface_name) - 1,
419cd2d7a5SSteven                     strlen ((const char *) hi->name)));
429cd2d7a5SSteven    bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
439cd2d7a5SSteven    hi = vnet_get_hw_interface (vnm, bif->hw_if_index);
449cd2d7a5SSteven    clib_memcpy(lacpif->bond_interface_name, hi->name,
459cd2d7a5SSteven                MIN (ARRAY_LEN (lacpif->bond_interface_name) - 1,
469cd2d7a5SSteven                     strlen ((const char *) hi->name)));
479cd2d7a5SSteven    clib_memcpy (lacpif->actor_system, sif->actor.system, 6);
489cd2d7a5SSteven    lacpif->actor_system_priority = sif->actor.system_priority;
499cd2d7a5SSteven    lacpif->actor_key = sif->actor.key;
509cd2d7a5SSteven    lacpif->actor_port_priority = sif->actor.port_priority;
519cd2d7a5SSteven    lacpif->actor_port_number = sif->actor.port_number;
529cd2d7a5SSteven    lacpif->actor_state = sif->actor.state;
539cd2d7a5SSteven    clib_memcpy (lacpif->partner_system, sif->partner.system, 6);
549cd2d7a5SSteven    lacpif->partner_system_priority = sif->partner.system_priority;
559cd2d7a5SSteven    lacpif->partner_key = sif->partner.key;
569cd2d7a5SSteven    lacpif->partner_port_priority = sif->partner.port_priority;
579cd2d7a5SSteven    lacpif->partner_port_number = sif->partner.port_number;
589cd2d7a5SSteven    lacpif->partner_state = sif->partner.state;
599cd2d7a5SSteven    lacpif->rx_state = sif->rx_state;
609cd2d7a5SSteven    lacpif->tx_state = sif->tx_state;
619cd2d7a5SSteven    lacpif->ptx_state = sif->ptx_state;
629cd2d7a5SSteven    lacpif->mux_state = sif->mux_state;
639cd2d7a5SSteven  );
649cd2d7a5SSteven  /* *INDENT-ON* */
659cd2d7a5SSteven
669cd2d7a5SSteven  *out_lacpifs = r_lacpifs;
679cd2d7a5SSteven
689cd2d7a5SSteven  return 0;
699cd2d7a5SSteven}
709cd2d7a5SSteven
719cd2d7a5SStevenstatic void
729cd2d7a5SStevenshow_lacp (vlib_main_t * vm, u32 * sw_if_indices)
739cd2d7a5SSteven{
749cd2d7a5SSteven  int i;
759cd2d7a5SSteven  slave_if_t *sif;
769cd2d7a5SSteven  bond_if_t *bif;
779cd2d7a5SSteven
789cd2d7a5SSteven  if (!sw_if_indices)
799cd2d7a5SSteven    return;
809cd2d7a5SSteven
819cd2d7a5SSteven  vlib_cli_output (vm, "%-55s %-32s %-32s", " ", "actor state",
829cd2d7a5SSteven		   "partner state");
839cd2d7a5SSteven  vlib_cli_output (vm, "%-25s %-12s %-16s %-31s  %-31s", "interface name",
849cd2d7a5SSteven		   "sw_if_index", "bond interface",
859cd2d7a5SSteven		   "exp/def/dis/col/syn/agg/tim/act",
869cd2d7a5SSteven		   "exp/def/dis/col/syn/agg/tim/act");
879cd2d7a5SSteven
889cd2d7a5SSteven  for (i = 0; i < vec_len (sw_if_indices); i++)
899cd2d7a5SSteven    {
909cd2d7a5SSteven      sif = bond_get_slave_by_sw_if_index (sw_if_indices[i]);
91bac326cbSSteven Luong      if (!sif || (sif->lacp_enabled == 0))
929cd2d7a5SSteven	continue;
939cd2d7a5SSteven      bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
949cd2d7a5SSteven      vlib_cli_output (vm,
959cd2d7a5SSteven		       "%-25U %-12d %-16U %3x %3x %3x %3x %3x %3x %3x %3x "
969cd2d7a5SSteven		       "%4x %3x %3x %3x %3x %3x %3x %3x",
979cd2d7a5SSteven		       format_vnet_sw_if_index_name, vnet_get_main (),
989cd2d7a5SSteven		       sif->sw_if_index, sif->sw_if_index,
999cd2d7a5SSteven		       format_vnet_sw_if_index_name, vnet_get_main (),
1009cd2d7a5SSteven		       bif->sw_if_index, lacp_bit_test (sif->actor.state, 7),
1019cd2d7a5SSteven		       lacp_bit_test (sif->actor.state, 6),
1029cd2d7a5SSteven		       lacp_bit_test (sif->actor.state, 5),
1039cd2d7a5SSteven		       lacp_bit_test (sif->actor.state, 4),
1049cd2d7a5SSteven		       lacp_bit_test (sif->actor.state, 3),
1059cd2d7a5SSteven		       lacp_bit_test (sif->actor.state, 2),
1069cd2d7a5SSteven		       lacp_bit_test (sif->actor.state, 1),
1079cd2d7a5SSteven		       lacp_bit_test (sif->actor.state, 0),
1089cd2d7a5SSteven		       lacp_bit_test (sif->partner.state, 7),
1099cd2d7a5SSteven		       lacp_bit_test (sif->partner.state, 6),
1109cd2d7a5SSteven		       lacp_bit_test (sif->partner.state, 5),
1119cd2d7a5SSteven		       lacp_bit_test (sif->partner.state, 4),
1129cd2d7a5SSteven		       lacp_bit_test (sif->partner.state, 3),
1139cd2d7a5SSteven		       lacp_bit_test (sif->partner.state, 2),
1149cd2d7a5SSteven		       lacp_bit_test (sif->partner.state, 1),
1159cd2d7a5SSteven		       lacp_bit_test (sif->partner.state, 0));
1169cd2d7a5SSteven      vlib_cli_output (vm,
1179cd2d7a5SSteven		       "  LAG ID: "
1189cd2d7a5SSteven		       "[(%04x,%02x-%02x-%02x-%02x-%02x-%02x,%04x,%04x,%04x), "
1199cd2d7a5SSteven		       "(%04x,%02x-%02x-%02x-%02x-%02x-%02x,%04x,%04x,%04x)]",
1209cd2d7a5SSteven		       ntohs (sif->actor.system_priority),
1219cd2d7a5SSteven		       sif->actor.system[0], sif->actor.system[1],
1229cd2d7a5SSteven		       sif->actor.system[2], sif->actor.system[3],
1239cd2d7a5SSteven		       sif->actor.system[4], sif->actor.system[5],
1249cd2d7a5SSteven		       ntohs (sif->actor.key),
1259cd2d7a5SSteven		       ntohs (sif->actor.port_priority),
1269cd2d7a5SSteven		       ntohs (sif->actor.port_number),
1279cd2d7a5SSteven		       ntohs (sif->partner.system_priority),
1289cd2d7a5SSteven		       sif->partner.system[0], sif->partner.system[1],
1299cd2d7a5SSteven		       sif->partner.system[2], sif->partner.system[3],
1309cd2d7a5SSteven		       sif->partner.system[4], sif->partner.system[5],
1319cd2d7a5SSteven		       ntohs (sif->partner.key),
1329cd2d7a5SSteven		       ntohs (sif->partner.port_priority),
1339cd2d7a5SSteven		       ntohs (sif->partner.port_number));
1349cd2d7a5SSteven      vlib_cli_output (vm,
1359cd2d7a5SSteven		       "  RX-state: %U, TX-state: %U, "
1369cd2d7a5SSteven		       "MUX-state: %U, PTX-state: %U",
1379cd2d7a5SSteven		       format_rx_sm_state, sif->rx_state, format_tx_sm_state,
1389cd2d7a5SSteven		       sif->tx_state, format_mux_sm_state, sif->mux_state,
1399cd2d7a5SSteven		       format_ptx_sm_state, sif->ptx_state);
1409cd2d7a5SSteven    }
1419cd2d7a5SSteven}
1429cd2d7a5SSteven
1439cd2d7a5SStevenstatic void
1449cd2d7a5SStevenshow_lacp_details (vlib_main_t * vm, u32 * sw_if_indices)
1459cd2d7a5SSteven{
1464168c4d9SSteven Luong  lacp_main_t *lm = &lacp_main;
1479cd2d7a5SSteven  slave_if_t *sif;
1489cd2d7a5SSteven  lacp_state_struct *state_entry;
1499cd2d7a5SSteven  int i;
1509cd2d7a5SSteven  f64 now;
1519cd2d7a5SSteven
1524168c4d9SSteven Luong  vlib_cli_output (vm, "Number of interfaces: %d", lm->lacp_int);
1539cd2d7a5SSteven  if (!sw_if_indices)
1549cd2d7a5SSteven    return;
1559cd2d7a5SSteven
1569cd2d7a5SSteven  now = vlib_time_now (vm);
1579cd2d7a5SSteven  for (i = 0; i < vec_len (sw_if_indices); i++)
1589cd2d7a5SSteven    {
1599cd2d7a5SSteven      sif = bond_get_slave_by_sw_if_index (sw_if_indices[i]);
160bac326cbSSteven Luong      if (!sif || (sif->lacp_enabled == 0))
1619cd2d7a5SSteven	continue;
1629cd2d7a5SSteven      vlib_cli_output (vm, "  %U", format_vnet_sw_if_index_name,
1639cd2d7a5SSteven		       vnet_get_main (), sif->sw_if_index);
16482c5dda4SSteven Luong      vlib_cli_output (vm, "    Good LACP PDUs received: %llu",
16582c5dda4SSteven Luong		       sif->pdu_received);
16682c5dda4SSteven Luong      vlib_cli_output (vm, "    Bad LACP PDUs received: %llu",
16782c5dda4SSteven Luong		       sif->bad_pdu_received);
16882c5dda4SSteven Luong      vlib_cli_output (vm, "    LACP PDUs sent: %llu", sif->pdu_sent);
16982c5dda4SSteven Luong      if (lacp_timer_is_running (sif->last_lacpdu_recd_time))
17082c5dda4SSteven Luong	vlib_cli_output (vm,
17182c5dda4SSteven Luong			 "    last LACP PDU received: %10.2f seconds ago",
17282c5dda4SSteven Luong			 now - sif->last_lacpdu_recd_time);
17382c5dda4SSteven Luong      if (lacp_timer_is_running (sif->last_lacpdu_sent_time))
17482c5dda4SSteven Luong	vlib_cli_output (vm, "    last LACP PDU sent: %10.2f seconds ago",
17582c5dda4SSteven Luong			 now - sif->last_lacpdu_sent_time);
17682c5dda4SSteven Luong      vlib_cli_output (vm, "    Good Marker PDUs received: %llu",
17782c5dda4SSteven Luong		       sif->marker_pdu_received);
17882c5dda4SSteven Luong      vlib_cli_output (vm, "    Bad Marker PDUs received: %llu",
17982c5dda4SSteven Luong		       sif->marker_bad_pdu_received);
18082c5dda4SSteven Luong      if (lacp_timer_is_running (sif->last_marker_pdu_recd_time))
18182c5dda4SSteven Luong	vlib_cli_output (vm,
18282c5dda4SSteven Luong			 "    last Marker PDU received: %10.2f seconds ago",
18382c5dda4SSteven Luong			 now - sif->last_marker_pdu_recd_time);
18482c5dda4SSteven Luong      if (lacp_timer_is_running (sif->last_marker_pdu_sent_time))
18582c5dda4SSteven Luong	vlib_cli_output (vm, "    last Marker PDU sent: %10.2f seconds ago",
18682c5dda4SSteven Luong			 now - sif->last_marker_pdu_sent_time);
1879cd2d7a5SSteven      vlib_cli_output (vm, "    debug: %d", sif->debug);
1889cd2d7a5SSteven      vlib_cli_output (vm, "    loopback port: %d", sif->loopback_port);
189bac326cbSSteven Luong      vlib_cli_output (vm, "    port_enabled: %d", sif->port_enabled);
1909cd2d7a5SSteven      vlib_cli_output (vm, "    port moved: %d", sif->port_moved);
1919cd2d7a5SSteven      vlib_cli_output (vm, "    ready_n: %d", sif->ready_n);
1929cd2d7a5SSteven      vlib_cli_output (vm, "    ready: %d", sif->ready);
1939cd2d7a5SSteven      vlib_cli_output (vm, "    Actor");
1949cd2d7a5SSteven      vlib_cli_output (vm, "      system: %U",
1959cd2d7a5SSteven		       format_ethernet_address, sif->actor.system);
1969cd2d7a5SSteven      vlib_cli_output (vm, "      system priority: %u",
1979cd2d7a5SSteven		       ntohs (sif->actor.system_priority));
1989cd2d7a5SSteven      vlib_cli_output (vm, "      key: %u", ntohs (sif->actor.key));
1999cd2d7a5SSteven      vlib_cli_output (vm, "      port priority: %u",
2009cd2d7a5SSteven		       ntohs (sif->actor.port_priority));
2019cd2d7a5SSteven      vlib_cli_output (vm, "      port number: %u",
2029cd2d7a5SSteven		       ntohs (sif->actor.port_number));
2039cd2d7a5SSteven      vlib_cli_output (vm, "      state: 0x%x", sif->actor.state);
2049cd2d7a5SSteven
2059cd2d7a5SSteven      state_entry = (lacp_state_struct *) & lacp_state_array;
2069cd2d7a5SSteven      while (state_entry->str)
2079cd2d7a5SSteven	{
2089cd2d7a5SSteven	  if (sif->actor.state & (1 << state_entry->bit))
2099cd2d7a5SSteven	    vlib_cli_output (vm, "        %s (%d)", state_entry->str,
2109cd2d7a5SSteven			     state_entry->bit);
2119cd2d7a5SSteven	  state_entry++;
2129cd2d7a5SSteven	}
2139cd2d7a5SSteven
2149cd2d7a5SSteven      vlib_cli_output (vm, "    Partner");
2159cd2d7a5SSteven      vlib_cli_output (vm, "      system: %U",
2169cd2d7a5SSteven		       format_ethernet_address, sif->partner.system);
2179cd2d7a5SSteven      vlib_cli_output (vm, "      system priority: %u",
2189cd2d7a5SSteven		       ntohs (sif->partner.system_priority));
2199cd2d7a5SSteven      vlib_cli_output (vm, "      key: %u", ntohs (sif->partner.key));
2209cd2d7a5SSteven      vlib_cli_output (vm, "      port priority: %u",
2219cd2d7a5SSteven		       ntohs (sif->partner.port_priority));
2229cd2d7a5SSteven      vlib_cli_output (vm, "      port number: %u",
2239cd2d7a5SSteven		       ntohs (sif->partner.port_number));
2249cd2d7a5SSteven      vlib_cli_output (vm, "      state: 0x%x", sif->partner.state);
2259cd2d7a5SSteven
2269cd2d7a5SSteven      state_entry = (lacp_state_struct *) & lacp_state_array;
2279cd2d7a5SSteven      while (state_entry->str)
2289cd2d7a5SSteven	{
2299cd2d7a5SSteven	  if (sif->partner.state & (1 << state_entry->bit))
2309cd2d7a5SSteven	    vlib_cli_output (vm, "        %s (%d)", state_entry->str,
2319cd2d7a5SSteven			     state_entry->bit);
2329cd2d7a5SSteven	  state_entry++;
2339cd2d7a5SSteven	}
2349cd2d7a5SSteven
2359cd2d7a5SSteven      if (!lacp_timer_is_running (sif->wait_while_timer))
2369cd2d7a5SSteven	vlib_cli_output (vm, "      wait while timer: not running");
2379cd2d7a5SSteven      else
23882c5dda4SSteven Luong	vlib_cli_output (vm, "      wait while timer: %10.2f seconds",
2399cd2d7a5SSteven			 sif->wait_while_timer - now);
2409cd2d7a5SSteven      if (!lacp_timer_is_running (sif->current_while_timer))
2419cd2d7a5SSteven	vlib_cli_output (vm, "      current while timer: not running");
2429cd2d7a5SSteven      else
24382c5dda4SSteven Luong	vlib_cli_output (vm, "      current while timer: %10.2f seconds",
2449cd2d7a5SSteven			 sif->current_while_timer - now);
2459cd2d7a5SSteven      if (!lacp_timer_is_running (sif->periodic_timer))
2469cd2d7a5SSteven	vlib_cli_output (vm, "      periodic timer: not running");
2479cd2d7a5SSteven      else
24882c5dda4SSteven Luong	vlib_cli_output (vm, "      periodic timer: %10.2f seconds",
2499cd2d7a5SSteven			 sif->periodic_timer - now);
2509cd2d7a5SSteven      vlib_cli_output (vm, "    RX-state: %U", format_rx_sm_state,
2519cd2d7a5SSteven		       sif->rx_state);
2529cd2d7a5SSteven      vlib_cli_output (vm, "    TX-state: %U", format_tx_sm_state,
2539cd2d7a5SSteven		       sif->tx_state);
2549cd2d7a5SSteven      vlib_cli_output (vm, "    MUX-state: %U", format_mux_sm_state,
2559cd2d7a5SSteven		       sif->mux_state);
2569cd2d7a5SSteven      vlib_cli_output (vm, "    PTX-state: %U", format_ptx_sm_state,
2579cd2d7a5SSteven		       sif->ptx_state);
2589cd2d7a5SSteven      vlib_cli_output (vm, "\n");
2599cd2d7a5SSteven    }
2609cd2d7a5SSteven}
2619cd2d7a5SSteven
2629cd2d7a5SStevenstatic clib_error_t *
2639cd2d7a5SStevenshow_lacp_fn (vlib_main_t * vm, unformat_input_t * input,
2649cd2d7a5SSteven	      vlib_cli_command_t * cmd)
2659cd2d7a5SSteven{
2669cd2d7a5SSteven  bond_main_t *bm = &bond_main;
2679cd2d7a5SSteven  vnet_main_t *vnm = &vnet_main;
2689cd2d7a5SSteven  slave_if_t *sif;
2699cd2d7a5SSteven  clib_error_t *error = 0;
2709cd2d7a5SSteven  u8 details = 0;
271ce2db6a6SSteven  u32 sw_if_index, *sw_if_indices = 0;
2729cd2d7a5SSteven
2739cd2d7a5SSteven  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2749cd2d7a5SSteven    {
2759cd2d7a5SSteven      if (unformat
276ce2db6a6SSteven	  (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
2779cd2d7a5SSteven	{
278ce2db6a6SSteven	  sif = bond_get_slave_by_sw_if_index (sw_if_index);
2799cd2d7a5SSteven	  if (!sif)
2809cd2d7a5SSteven	    {
2819cd2d7a5SSteven	      error = clib_error_return (0, "interface is not enslaved");
2829cd2d7a5SSteven	      goto done;
2839cd2d7a5SSteven	    }
2849cd2d7a5SSteven	  vec_add1 (sw_if_indices, sif->sw_if_index);
2859cd2d7a5SSteven	}
2869cd2d7a5SSteven      else if (unformat (input, "details"))
2879cd2d7a5SSteven	details = 1;
2889cd2d7a5SSteven      else
2899cd2d7a5SSteven	{
2909cd2d7a5SSteven	  error = clib_error_return (0, "unknown input `%U'",
2919cd2d7a5SSteven				     format_unformat_error, input);
2929cd2d7a5SSteven	  goto done;
2939cd2d7a5SSteven	}
2949cd2d7a5SSteven    }
2959cd2d7a5SSteven
2969cd2d7a5SSteven  if (vec_len (sw_if_indices) == 0)
2979cd2d7a5SSteven    {
2989cd2d7a5SSteven      pool_foreach (sif, bm->neighbors,
2999cd2d7a5SSteven		    vec_add1 (sw_if_indices, sif->sw_if_index);
3009cd2d7a5SSteven	);
3019cd2d7a5SSteven    }
3029cd2d7a5SSteven
3039cd2d7a5SSteven  if (details)
3049cd2d7a5SSteven    show_lacp_details (vm, sw_if_indices);
3059cd2d7a5SSteven  else
3069cd2d7a5SSteven    show_lacp (vm, sw_if_indices);
3079cd2d7a5SSteven
3089cd2d7a5SStevendone:
3099cd2d7a5SSteven  vec_free (sw_if_indices);
3109cd2d7a5SSteven  return error;
3119cd2d7a5SSteven}
3129cd2d7a5SSteven
3139cd2d7a5SSteven/* *INDENT-OFF* */
3149cd2d7a5SStevenVLIB_CLI_COMMAND (show_lacp_command, static) = {
3159cd2d7a5SSteven  .path = "show lacp",
3169cd2d7a5SSteven  .short_help = "show lacp [<interface>] [details]",
3179cd2d7a5SSteven  .function = show_lacp_fn,
318cda35b38SSteven Luong  .is_mp_safe = 1,
3199cd2d7a5SSteven};
3209cd2d7a5SSteven/* *INDENT-ON* */
3219cd2d7a5SSteven
3229cd2d7a5SStevenstatic clib_error_t *
3239cd2d7a5SStevendebug_lacp_command_fn (vlib_main_t * vm, unformat_input_t * input,
3249cd2d7a5SSteven		       vlib_cli_command_t * cmd)
3259cd2d7a5SSteven{
3269cd2d7a5SSteven  unformat_input_t _line_input, *line_input = &_line_input;
3279cd2d7a5SSteven  clib_error_t *error = NULL;
3289cd2d7a5SSteven  lacp_main_t *lm = &lacp_main;
3299cd2d7a5SSteven  u8 onoff = 0;
3309cd2d7a5SSteven  u8 input_found = 0;
331ce2db6a6SSteven  u32 sw_if_index = ~0;
3329cd2d7a5SSteven  slave_if_t *sif;
3339cd2d7a5SSteven  vnet_main_t *vnm = vnet_get_main ();
3349cd2d7a5SSteven
3359cd2d7a5SSteven  /* Get a line of input. */
3369cd2d7a5SSteven  if (!unformat_user (input, unformat_line_input, line_input))
3379cd2d7a5SSteven    return clib_error_return (0, "missing argument");
3389cd2d7a5SSteven
3399cd2d7a5SSteven  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3409cd2d7a5SSteven    {
341