Clean up old datapath code in ACL plugin.
[vpp.git] / src / plugins / acl / l2sess_node.c
diff --git a/src/plugins/acl/l2sess_node.c b/src/plugins/acl/l2sess_node.c
deleted file mode 100644 (file)
index 689d216..0000000
+++ /dev/null
@@ -1,763 +0,0 @@
-/*
- * 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 <netinet/in.h>
-#include <vlib/vlib.h>
-#include <vnet/vnet.h>
-#include <vnet/pg/pg.h>
-#include <vppinfra/error.h>
-#include <acl/l2sess.h>
-#include <vnet/l2/l2_classify.h>
-
-
-typedef struct
-{
-  u32 next_index;
-  u32 sw_if_index;
-  u32 trace_flags;
-  u32 session_tables[2];
-  u32 session_nexts[2];
-  u8 l4_proto;
-} l2sess_trace_t;
-
-/* packet trace format function */
-
-#define _(node_name, node_var, is_out, is_ip6, is_track) \
-static u8 * format_## node_var ##_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 *); \
-  l2sess_trace_t * t = va_arg (*args, l2sess_trace_t *); \
- \
-  s = format (s, node_name ": sw_if_index %d, next index %d trace_flags %08x L4 proto %d\n" \
-                           "                 tables [ %d, %d ] nexts [ %d, %d ]", \
-              t->sw_if_index, t->next_index, t->trace_flags, t->l4_proto, \
-              t->session_tables[0], t->session_tables[1], \
-              t->session_nexts[0], t->session_nexts[1]); \
-  return s; \
-}
-foreach_l2sess_node
-#undef _
-#define foreach_l2sess_error \
-_(SWAPPED, "Mac swap packets processed")
-  typedef enum
-{
-#define _(sym,str) L2SESS_ERROR_##sym,
-  foreach_l2sess_error
-#undef _
-    L2SESS_N_ERROR,
-} l2sess_error_t;
-
-static char *l2sess_error_strings[] = {
-#define _(sym,string) string,
-  foreach_l2sess_error
-#undef _
-};
-
-typedef enum
-{
-  L2SESS_NEXT_DROP,
-  L2SESS_N_NEXT,
-} l2sess_next_t;
-
-u8
-l2sess_get_l4_proto (vlib_buffer_t * b0, int node_is_ip6)
-{
-  u8 proto;
-  int proto_offset;
-  if (node_is_ip6)
-    {
-      proto_offset = 20;
-    }
-  else
-    {
-      proto_offset = 23;
-    }
-  proto = *((u8 *) vlib_buffer_get_current (b0) + proto_offset);
-  return proto;
-}
-
-
-u8
-l2sess_get_tcp_flags (vlib_buffer_t * b0, int node_is_ip6)
-{
-  u8 flags;
-  int flags_offset;
-  if (node_is_ip6)
-    {
-      flags_offset = 14 + 40 + 13;     /* FIXME: no extension headers assumed */
-    }
-  else
-    {
-      flags_offset = 14 + 20 + 13;
-    }
-  flags = *((u8 *) vlib_buffer_get_current (b0) + flags_offset);
-  return flags;
-}
-
-static inline int
-l4_tcp_or_udp (u8 proto)
-{
-  return ((proto == 6) || (proto == 17));
-}
-
-void
-l2sess_get_session_tables (l2sess_main_t * sm, u32 sw_if_index,
-                          int node_is_out, int node_is_ip6, u8 l4_proto,
-                          u32 * session_tables)
-{
-/*
- * Based on the direction, l3 and l4 protocol, fill a u32[2] array:
- * [0] is index for the "direct match" path, [1] is for "mirrored match".
- * Store the indices of the tables to add the session to in session_tables[]
- */
-  l2_output_classify_main_t *l2om = &l2_output_classify_main;
-  l2_input_classify_main_t *l2im = &l2_input_classify_main;
-
-  u32 output_table_index;
-  u32 input_table_index;
-
-  if (!l4_tcp_or_udp (l4_proto))
-    {
-      return;
-    }
-
-  if (node_is_ip6)
-    {
-      vec_validate_init_empty (l2im->
-                              classify_table_index_by_sw_if_index
-                              [L2_INPUT_CLASSIFY_TABLE_IP6], sw_if_index,
-                              ~0);
-      input_table_index =
-       l2im->
-       classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP6]
-       [sw_if_index];
-      vec_validate_init_empty (l2om->
-                              classify_table_index_by_sw_if_index
-                              [L2_OUTPUT_CLASSIFY_TABLE_IP6], sw_if_index,
-                              ~0);
-      output_table_index =
-       l2om->
-       classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_IP6]
-       [sw_if_index];
-    }
-  else
-    {
-      vec_validate_init_empty (l2im->
-                              classify_table_index_by_sw_if_index
-                              [L2_INPUT_CLASSIFY_TABLE_IP4], sw_if_index,
-                              ~0);
-      input_table_index =
-       l2im->
-       classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP4]
-       [sw_if_index];
-      vec_validate_init_empty (l2om->
-                              classify_table_index_by_sw_if_index
-                              [L2_OUTPUT_CLASSIFY_TABLE_IP4], sw_if_index,
-                              ~0);
-      output_table_index =
-       l2om->
-       classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_IP4]
-       [sw_if_index];
-    }
-
-  if (node_is_out)
-    {
-      session_tables[0] = output_table_index;
-      session_tables[1] = input_table_index;
-    }
-  else
-    {
-      session_tables[0] = input_table_index;
-      session_tables[1] = output_table_index;
-    }
-}
-
-void
-l2sess_get_session_nexts (l2sess_main_t * sm, u32 sw_if_index,
-                         int node_is_out, int node_is_ip6, u8 l4_proto,
-                         u32 * session_nexts)
-{
-/*
- * Based on the direction, l3 and l4 protocol, fill a u32[2] array:
- * [0] is the index for the "direct match" path, [1] is for "mirrored match".
- * Store the match_next_index in session_nexts[] for a new session entry which is being added to session tables.
- */
-  u32 input_node_index;
-  u32 output_node_index;
-
-  if (!l4_tcp_or_udp (l4_proto))
-    {
-      return;
-    }
-
-  input_node_index =
-    sm->next_slot_track_node_by_is_ip6_is_out[node_is_ip6][0];
-  output_node_index =
-    sm->next_slot_track_node_by_is_ip6_is_out[node_is_ip6][1];
-
-  if (node_is_out)
-    {
-      session_nexts[0] = output_node_index;
-      session_nexts[1] = input_node_index;
-    }
-  else
-    {
-      session_nexts[0] = input_node_index;
-      session_nexts[1] = output_node_index;
-    }
-}
-
-
-static inline void
-swap_bytes (vlib_buffer_t * b0, int off_a, int off_b, int nbytes)
-{
-  u8 tmp;
-  u8 *pa = vlib_buffer_get_current (b0) + off_a;
-  u8 *pb = vlib_buffer_get_current (b0) + off_b;
-  while (nbytes--)
-    {
-      tmp = *pa;
-      *pa++ = *pb;
-      *pb++ = tmp;
-    }
-}
-
-/*
- * This quite pro[bv]ably is a terrible idea performance wise. Moreso doing it twice.
- * Would having a long (ish) chunk of memory work better for this ?
- * We will see when we get to the performance of this.
- */
-void
-l2sess_flip_l3l4_fields (vlib_buffer_t * b0, int node_is_ip6, u8 l4_proto)
-{
-  if (!l4_tcp_or_udp (l4_proto))
-    {
-      return;
-    }
-  if (node_is_ip6)
-    {
-      swap_bytes (b0, 22, 38, 16);     /* L3 */
-      swap_bytes (b0, 54, 56, 2);      /* L4 (when no EH!) */
-    }
-  else
-    {
-      swap_bytes (b0, 26, 30, 4);      /* L3 */
-      swap_bytes (b0, 34, 36, 2);      /* L4 */
-    }
-}
-
-void
-l2sess_add_session (vlib_buffer_t * b0, int node_is_out, int node_is_ip6,
-                   u32 session_table, u32 session_match_next,
-                   u32 opaque_index)
-{
-  vnet_classify_main_t *cm = &vnet_classify_main;
-  u32 action = 0;
-  u32 metadata = 0;
-
-#ifdef DEBUG_SESSIONS
-  printf ("Adding session to table %d with next %d\n", session_table,
-         session_match_next);
-#endif
-  vnet_classify_add_del_session (cm, session_table,
-                                vlib_buffer_get_current (b0),
-                                session_match_next, opaque_index, 0, action,
-                                metadata, 1);
-}
-
-
-
-static void *
-get_ptr_to_offset (vlib_buffer_t * b0, int offset)
-{
-  u8 *p = vlib_buffer_get_current (b0) + offset;
-  return p;
-}
-
-
-/*
- * FIXME: Hardcoded offsets are ugly, although if casting to structs one
- * would need to take care about alignment.. So let's for now be naive and simple.
- */
-
-void
-session_store_ip4_l3l4_info (vlib_buffer_t * b0, l2s_session_t * sess,
-                            int node_is_out)
-{
-  clib_memcpy (&sess->side[1 - node_is_out].addr.ip4,
-              get_ptr_to_offset (b0, 26), 4);
-  clib_memcpy (&sess->side[node_is_out].addr.ip4, get_ptr_to_offset (b0, 30),
-              4);
-  sess->side[1 - node_is_out].port =
-    ntohs (*(u16 *) get_ptr_to_offset (b0, 34));
-  sess->side[node_is_out].port = ntohs (*(u16 *) get_ptr_to_offset (b0, 36));
-}
-
-void
-session_store_ip6_l3l4_info (vlib_buffer_t * b0, l2s_session_t * sess,
-                            int node_is_out)
-{
-  clib_memcpy (&sess->side[1 - node_is_out].addr.ip6,
-              get_ptr_to_offset (b0, 22), 16);
-  clib_memcpy (&sess->side[node_is_out].addr.ip4, get_ptr_to_offset (b0, 38),
-              16);
-  sess->side[1 - node_is_out].port =
-    ntohs (*(u16 *) get_ptr_to_offset (b0, 54));
-  sess->side[node_is_out].port = ntohs (*(u16 *) get_ptr_to_offset (b0, 56));
-}
-
-static void
-build_match_from_session (l2sess_main_t * sm, u8 * match,
-                         l2s_session_t * sess, int is_out)
-{
-  if (sess->is_ip6)
-    {
-      match[20] = sess->l4_proto;
-      clib_memcpy (&match[22], &sess->side[1 - is_out].addr.ip6, 16);
-      clib_memcpy (&match[38], &sess->side[is_out].addr.ip4, 16);
-      *(u16 *) & match[54] = htons (sess->side[1 - is_out].port);
-      *(u16 *) & match[56] = htons (sess->side[is_out].port);
-    }
-  else
-    {
-      match[23] = sess->l4_proto;
-      clib_memcpy (&match[26], &sess->side[1 - is_out].addr.ip6, 4);
-      clib_memcpy (&match[30], &sess->side[is_out].addr.ip4, 4);
-      *(u16 *) & match[34] = htons (sess->side[1 - is_out].port);
-      *(u16 *) & match[36] = htons (sess->side[is_out].port);
-    }
-}
-
-static void
-delete_session (l2sess_main_t * sm, u32 sw_if_index, u32 session_index)
-{
-  vnet_classify_main_t *cm = &vnet_classify_main;
-  u8 match[5 * 16];            /* For building the mock of the packet to delete the classifier session */
-  u32 session_tables[2] = { ~0, ~0 };
-  l2s_session_t *sess = sm->sessions + session_index;
-  if (pool_is_free (sm->sessions, sess))
-    {
-      sm->counter_attempted_delete_free_session++;
-      return;
-    }
-  l2sess_get_session_tables (sm, sw_if_index, 0, sess->is_ip6, sess->l4_proto,
-                            session_tables);
-  if (session_tables[1] != ~0)
-    {
-      build_match_from_session (sm, match, sess, 1);
-      vnet_classify_add_del_session (cm, session_tables[1], match, 0, 0, 0, 0,
-                                    0, 0);
-    }
-  if (session_tables[1] != ~0)
-    {
-      build_match_from_session (sm, match, sess, 1);
-      vnet_classify_add_del_session (cm, session_tables[1], match, 0, 0, 0, 0,
-                                    0, 0);
-    }
-  pool_put (sm->sessions, sess);
-}
-
-static void
-udp_session_account_buffer (vlib_buffer_t * b0, l2s_session_t * s,
-                           int which_side, u64 now)
-{
-  l2s_session_side_t *ss = &s->side[which_side];
-  ss->active_time = now;
-  ss->n_packets++;
-  ss->n_bytes += b0->current_data + b0->current_length;
-}
-
-static inline u64
-udp_session_get_timeout (l2sess_main_t * sm, l2s_session_t * sess, u64 now)
-{
-  return (sm->udp_session_idle_timeout);
-}
-
-static void
-tcp_session_account_buffer (vlib_buffer_t * b0, l2s_session_t * s,
-                           int which_side, u64 now)
-{
-  l2s_session_side_t *ss = &s->side[which_side];
-  ss->active_time = now;
-  ss->n_packets++;
-  ss->n_bytes += b0->current_data + b0->current_length;
-  /* Very very lightweight TCP state tracking: just record which flags were seen */
-  s->tcp_flags_seen |=
-    l2sess_get_tcp_flags (b0, s->is_ip6) << (8 * which_side);
-}
-
-/*
- * Since we are tracking for the purposes of timing the sessions out,
- * we mostly care about two states: established (maximize the idle timeouts)
- * and transient (halfopen/halfclosed/reset) - we need to have a reasonably short timeout to
- * quickly get rid of sessions but not short enough to violate the TCP specs.
- */
-
-static inline u64
-tcp_session_get_timeout (l2sess_main_t * sm, l2s_session_t * sess, u64 now)
-{
-  /* seen both SYNs and ACKs but not FINs means we are in establshed state */
-  u16 masked_flags =
-    sess->tcp_flags_seen & ((TCP_FLAGS_RSTFINACKSYN << 8) +
-                           TCP_FLAGS_RSTFINACKSYN);
-  if (((TCP_FLAGS_ACKSYN << 8) + TCP_FLAGS_ACKSYN) == masked_flags)
-    {
-      return (sm->tcp_session_idle_timeout);
-    }
-  else
-    {
-      return (sm->tcp_session_transient_timeout);
-    }
-}
-
-static inline u64
-session_get_timeout (l2sess_main_t * sm, l2s_session_t * sess, u64 now)
-{
-  u64 timeout;
-
-  switch (sess->l4_proto)
-    {
-    case 6:
-      timeout = tcp_session_get_timeout (sm, sess, now);
-      break;
-    case 17:
-      timeout = udp_session_get_timeout (sm, sess, now);
-      break;
-    default:
-      timeout = 0;
-    }
-
-  return timeout;
-}
-
-static inline u64
-get_session_last_active_time(l2s_session_t * sess)
-{
-  u64 last_active =
-    sess->side[0].active_time >
-    sess->side[1].active_time ? sess->side[0].active_time : sess->side[1].
-    active_time;
-  return last_active;
-}
-
-static int
-session_is_alive (l2sess_main_t * sm, l2s_session_t * sess, u64 now, u64 *last_active_cache)
-{
-  u64 last_active = get_session_last_active_time(sess);
-  u64 timeout = session_get_timeout (sm, sess, now);
-  int is_alive = ((now - last_active) < timeout);
-  if (last_active_cache)
-    *last_active_cache = last_active;
-  return is_alive;
-}
-
-static void
-check_idle_sessions (l2sess_main_t * sm, u32 sw_if_index, u64 now)
-{
-  sm->timer_wheel_next_expiring_time = 0;
-  sm->data_from_advancing_timing_wheel
-    =
-    timing_wheel_advance (&sm->timing_wheel, now,
-                         sm->data_from_advancing_timing_wheel,
-                         &sm->timer_wheel_next_expiring_time);
-#ifdef DEBUG_SESSIONS_VERBOSE
-  {
-    clib_time_t *ct = &sm->vlib_main->clib_time;
-    f64 ctime;
-    ctime = now * ct->seconds_per_clock;
-    clib_warning ("Now        : %U", format_time_interval, "h:m:s:u", ctime);
-    ctime = sm->timer_wheel_next_expiring_time * ct->seconds_per_clock;
-    clib_warning ("Next expire: %U", format_time_interval, "h:m:s:u", ctime);
-    clib_warning ("Expired items: %d",
-                 (int) vec_len (sm->data_from_advancing_timing_wheel));
-  }
-#endif
-
-  sm->timer_wheel_next_expiring_time = now + sm->timer_wheel_tick;
-  if (PREDICT_FALSE ( 0 == sm->data_from_advancing_timing_wheel )) {
-    return;
-  }
-
-  if (PREDICT_FALSE (_vec_len (sm->data_from_advancing_timing_wheel) > 0))
-    {
-      uword i;
-      for (i = 0; i < _vec_len (sm->data_from_advancing_timing_wheel); i++)
-       {
-         u32 session_index = sm->data_from_advancing_timing_wheel[i];
-         if (!pool_is_free_index (sm->sessions, session_index))
-           {
-             l2s_session_t *sess = sm->sessions + session_index;
-              u64 last_active;
-              if (session_is_alive (sm, sess, now, &last_active))
-                {
-#ifdef DEBUG_SESSIONS
-             clib_warning ("Restarting timer for session %d", (int) session_index);
-#endif
-                    /* Pretend we did this in the past, at last_active moment */
-                    timing_wheel_insert (&sm->timing_wheel,
-                                         last_active + session_get_timeout (sm, sess,
-                                                                    last_active),
-                                         session_index);
-                }
-              else
-                {
-#ifdef DEBUG_SESSIONS
-             clib_warning ("Deleting session %d", (int) session_index);
-#endif
-             delete_session (sm, sw_if_index, session_index);
-                }
-           }
-       }
-      _vec_len (sm->data_from_advancing_timing_wheel) = 0;
-    }
-}
-
-static uword
-l2sess_node_fn (vlib_main_t * vm,
-               vlib_node_runtime_t * node, vlib_frame_t * frame,
-                int node_is_out, int node_is_ip6, int node_is_track,
-                u32 *feat_next_node_index)
-{
-  u32 n_left_from, *from, *to_next;
-  l2sess_next_t next_index;
-  u32 pkts_swapped = 0;
-  u32 feature_bitmap0;
-  u32 trace_flags0;
-
-  l2sess_main_t *sm = &l2sess_main;
-
-  from = vlib_frame_vector_args (frame);
-  n_left_from = frame->n_vectors;
-  next_index = node->cached_next_index;
-
-  while (n_left_from > 0)
-    {
-      u32 n_left_to_next;
-
-      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
-
-      /* Only a single loop for now for simplicity */
-
-      while (n_left_from > 0 && n_left_to_next > 0)
-       {
-         u32 bi0;
-         vlib_buffer_t *b0;
-         u32 next0 = L2SESS_NEXT_DROP;
-         u32 sw_if_index0;
-         //ethernet_header_t *en0;
-
-         /* speculatively enqueue b0 to the current next frame */
-         bi0 = from[0];
-         to_next[0] = bi0;
-         from += 1;
-         to_next += 1;
-         n_left_from -= 1;
-         n_left_to_next -= 1;
-
-         b0 = vlib_get_buffer (vm, bi0);
-         //en0 = vlib_buffer_get_current (b0);
-
-/*
- *     node_is_out : 1 = is output, 0 = is input
- *     node_is_ip6 : 1 = is ip6, 0 = is ip4
- *     node_is_track : 1 = is a state tracking node, 0 - is a session addition node
- *
- *     The below code adjust the behavior according to these parameters.
- */
-         {
-           u32 session_tables[2] = { ~0, ~0 };
-           u32 session_nexts[2] = { ~0, ~0 };
-           u8 l4_proto;
-           u64 now = clib_cpu_time_now ();
-
-           trace_flags0 = 0;
-           if (node_is_out)
-             {
-               sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
-             }
-           else
-             {
-               sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
-             }
-           /* potentially also remove the nodes here */
-           feature_bitmap0 = vnet_buffer (b0)->l2.feature_bitmap;
-
-           if (node_is_track)
-             {
-               u32 sess_index = vnet_buffer (b0)->l2_classify.opaque_index;
-               l2s_session_t *sess = sm->sessions + sess_index;
-               l4_proto = sess->l4_proto;
-
-               if (session_is_alive (sm, sess, now, 0))
-                 {
-                   if (6 == l4_proto)
-                     {
-                       tcp_session_account_buffer (b0, sess, node_is_out,
-                                                   now);
-                     }
-                   else
-                     {
-                       udp_session_account_buffer (b0, sess, node_is_out,
-                                                   now);
-                     }
-                 }
-               else
-                 {
-                   timing_wheel_delete (&sm->timing_wheel, sess_index);
-                   delete_session (sm, sw_if_index0, sess_index);
-                   /* FIXME: drop the packet that hit the obsolete node, for now. We really ought to recycle it. */
-                   next0 = 0;
-                 }
-             }
-           else
-             {
-               /*
-                * "-add" node: take l2opaque which arrived to us, and deduce
-                * the tables out of that. ~0 means the topmost classifier table
-                * applied for this AF on the RX(for input)/TX(for output)) sw_if_index.
-                * Also add the mirrored session to the paired table.
-                */
-               l2s_session_t *sess;
-               u32 sess_index;
-
-               l4_proto = l2sess_get_l4_proto (b0, node_is_ip6);
-
-               pool_get (sm->sessions, sess);
-               sess_index = sess - sm->sessions;
-               sess->create_time = now;
-               sess->side[node_is_out].active_time = now;
-               sess->side[1 - node_is_out].active_time = now;
-               sess->l4_proto = l4_proto;
-               sess->is_ip6 = node_is_ip6;
-               if (node_is_ip6)
-                 {
-                   session_store_ip6_l3l4_info (b0, sess, node_is_out);
-                 }
-               else
-                 {
-                   session_store_ip4_l3l4_info (b0, sess, node_is_out);
-                 }
-
-               l2sess_get_session_tables (sm, sw_if_index0, node_is_out,
-                                          node_is_ip6, l4_proto,
-                                          session_tables);
-               l2sess_get_session_nexts (sm, sw_if_index0, node_is_out,
-                                         node_is_ip6, l4_proto,
-                                         session_nexts);
-               l2sess_flip_l3l4_fields (b0, node_is_ip6, l4_proto);
-               if (session_tables[1] != ~0)
-                 {
-                   l2sess_add_session (b0, node_is_out, node_is_ip6,
-                                       session_tables[1], session_nexts[1],
-                                       sess_index);
-                 }
-               l2sess_flip_l3l4_fields (b0, node_is_ip6, l4_proto);
-               if (session_tables[0] != ~0)
-                 {
-                   l2sess_add_session (b0, node_is_out, node_is_ip6,
-                                       session_tables[0], session_nexts[0],
-                                       sess_index);
-                 }
-               if (6 == sess->l4_proto)
-                 {
-                   tcp_session_account_buffer (b0, sess, node_is_out, now);
-                 }
-               else
-                 {
-                   udp_session_account_buffer (b0, sess, node_is_out, now);
-                 }
-               timing_wheel_insert (&sm->timing_wheel,
-                                    now + session_get_timeout (sm, sess,
-                                                               now),
-                                    sess_index);
-             }
-
-           if (now >= sm->timer_wheel_next_expiring_time)
-             {
-               check_idle_sessions (sm, sw_if_index0, now);
-             }
-
-           next0 = feat_bitmap_get_next_node_index (feat_next_node_index,
-                                                  feature_bitmap0);
-
-           if (next0 >= node->n_next_nodes)
-             {
-               trace_flags0 |= 1;
-             }
-
-           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
-                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
-             {
-               l2sess_trace_t *t =
-                 vlib_add_trace (vm, node, b0, sizeof (*t));
-               t->sw_if_index = sw_if_index0;
-               t->next_index = next0;
-               t->trace_flags = trace_flags0;
-               t->l4_proto = l4_proto;
-               t->session_tables[0] = session_tables[0];
-               t->session_tables[1] = session_tables[1];
-               t->session_nexts[0] = session_nexts[0];
-               t->session_nexts[1] = session_nexts[1];
-             }
-
-         }
-         pkts_swapped += 1;
-         if (next0 >= node->n_next_nodes)
-           {
-             next0 = 0;
-           }
-
-         /* verify speculative enqueue, maybe switch current next frame */
-         vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
-                                          to_next, n_left_to_next,
-                                          bi0, next0);
-       }
-
-      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
-    }
-  vlib_node_increment_counter (vm, node->node_index,
-                              L2SESS_ERROR_SWAPPED, pkts_swapped);
-  return frame->n_vectors;
-}
-
-
-#define _(node_name, node_var, is_out, is_ip6, is_track) \
-static uword                                             \
-node_var ## node_fn (vlib_main_t * vm,                   \
-                  vlib_node_runtime_t * node,            \
-                  vlib_frame_t * frame)                  \
-{                                                        \
-  l2sess_main_t *sm = &l2sess_main;                      \
-  return l2sess_node_fn(vm, node, frame,                 \
-                        is_out, is_ip6, is_track,        \
-                        sm->node_var ## _feat_next_node_index);  \
-}                                                        \
-VLIB_REGISTER_NODE (node_var) = {                        \
-  .function = node_var ## node_fn,                       \
-  .name = node_name,                                     \
-  .vector_size = sizeof (u32),                           \
-  .format_trace = format_ ## node_var ## _trace,         \
-  .type = VLIB_NODE_TYPE_INTERNAL,                       \
-                                                         \
-  .n_errors = ARRAY_LEN(l2sess_error_strings),           \
-  .error_strings = l2sess_error_strings,                 \
-                                                         \
-  .n_next_nodes = L2SESS_N_NEXT,                         \
-  .next_nodes = {                                        \
-        [L2SESS_NEXT_DROP] = "error-drop",               \
-  },                                                     \
-};
-foreach_l2sess_node
-#undef _