aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/bier/bier_entry.c
diff options
context:
space:
mode:
authorNeale Ranns <nranns@cisco.com>2019-10-14 08:52:43 -0700
committerDamjan Marion <dmarion@me.com>2019-10-14 22:43:13 +0000
commita66020becd7d01eefea55244cbcf5df9679a9443 (patch)
tree5cfe7b89b470b8db5afd7c5c491f945142f95563 /src/vnet/bier/bier_entry.c
parentef3c11ca93b651611af33ab3e5d64217504d221d (diff)
fib: recursive calculation leads to delegate pool realloc
Type: fix Change-Id: Ib7ac53d1b59b641ccd3b1d733107d7f1ba174314 Signed-off-by: Neale Ranns <nranns@cisco.com>
Diffstat (limited to 'src/vnet/bier/bier_entry.c')
0 files changed, 0 insertions, 0 deletions
id='n141' href='#n141'>141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
/*
 * Copyright (c) 2015 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 <vnet/ip/ip.h>
#include <vnet/ip/ip_punt_drop.h>
#include <vnet/policer/policer.h>
#include <vnet/policer/police_inlines.h>
#include <vnet/fib/fib_path_list.h>

ip_punt_redirect_cfg_t ip_punt_redirect_cfg;

u8 *
format_ip_punt_redirect_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 *);
  ip_punt_redirect_trace_t *t = va_arg (*args, ip_punt_redirect_trace_t *);

  if (INDEX_INVALID == t->rrxi)
    s = format (s, "drop");
  else
    s = format (s, "via redirect:%d", t->rrxi);

  return s;
}

static void
ip_punt_redirect_stack (ip_punt_redirect_rx_t * ipr)
{
  dpo_id_t dpo = DPO_INVALID;
  vlib_node_t *pnode;

  fib_path_list_contribute_forwarding (ipr->pl,
				       ipr->payload_type,
				       FIB_PATH_LIST_FWD_FLAG_COLLAPSE, &dpo);

  if (FIB_PROTOCOL_IP4 == ipr->fproto)
    pnode =
      vlib_get_node_by_name (vlib_get_main (), (u8 *) "ip4-punt-redirect");
  else
    pnode =
      vlib_get_node_by_name (vlib_get_main (), (u8 *) "ip6-punt-redirect");

  dpo_stack_from_node (pnode->index, &ipr->dpo, &dpo);
  dpo_reset (&dpo);
}

index_t
ip_punt_redirect_find (fib_protocol_t fproto, u32 rx_sw_if_index)
{
  index_t *rxs;

  rxs = ip_punt_redirect_cfg.redirect_by_rx_sw_if_index[fproto];

  if (vec_len (rxs) <= rx_sw_if_index)
    return (INDEX_INVALID);

  return rxs[rx_sw_if_index];
}

void
ip_punt_redirect_add (fib_protocol_t fproto,
		      u32 rx_sw_if_index,
		      fib_forward_chain_type_t ct, fib_route_path_t * rpaths)
{
  ip_punt_redirect_rx_t *ipr;
  index_t ipri;

  if (~0 == rx_sw_if_index)
    rx_sw_if_index = 0;

  vec_validate_init_empty (ip_punt_redirect_cfg.redirect_by_rx_sw_if_index
			   [fproto], rx_sw_if_index, INDEX_INVALID);

  pool_get (ip_punt_redirect_cfg.pool, ipr);
  ipri = ipr - ip_punt_redirect_cfg.pool;

  ip_punt_redirect_cfg.redirect_by_rx_sw_if_index[fproto][rx_sw_if_index] =
    ipri;

  fib_node_init (&ipr->node, FIB_NODE_TYPE_IP_PUNT_REDIRECT);
  ipr->fproto = fproto;
  ipr->payload_type = ct;

  ipr->pl = fib_path_list_create (FIB_PATH_LIST_FLAG_NO_URPF, rpaths);

  ipr->sibling = fib_path_list_child_add (ipr->pl,
					  FIB_NODE_TYPE_IP_PUNT_REDIRECT,
					  ipri);

  ip_punt_redirect_stack (ipr);
}

void
ip_punt_redirect_del (fib_protocol_t fproto, u32 rx_sw_if_index)
{
  ip_punt_redirect_rx_t *ipr;
  index_t *rxs;

  if (~0 == rx_sw_if_index)
    rx_sw_if_index = 0;

  rxs = ip_punt_redirect_cfg.redirect_by_rx_sw_if_index[fproto];

  if ((vec_len (rxs) <= rx_sw_if_index) ||
      (INDEX_INVALID == rxs[rx_sw_if_index]))
    return;

  ipr = ip_punt_redirect_get (rxs[rx_sw_if_index]);

  fib_path_list_child_remove (ipr->pl, ipr->sibling);
  dpo_reset (&ipr->dpo);
  pool_put (ip_punt_redirect_cfg.pool, ipr);

  rxs[rx_sw_if_index] = INDEX_INVALID;
}

u8 *
format_ip_punt_redirect (u8 * s, va_list * args)
{
  fib_protocol_t fproto = va_arg (*args, int);
  ip_punt_redirect_rx_t *rx;
  index_t *rxs;
  u32 rx_sw_if_index;
  vnet_main_t *vnm = vnet_get_main ();

  rxs = ip_punt_redirect_cfg.redirect_by_rx_sw_if_index[fproto];

  vec_foreach_index (rx_sw_if_index, rxs)
  {
    if (INDEX_INVALID == rxs[rx_sw_if_index])
      continue;

    rx = ip_punt_redirect_get (rxs[rx_sw_if_index]);

    s = format (s, " rx %U via:\n",
		format_vnet_sw_interface_name, vnm,
		vnet_get_sw_interface (vnm, rx_sw_if_index));
    s = format (s, " %U", format_fib_path_list, rx->pl, 2);
    s = format (s, " forwarding\n", format_dpo_id, &rx->dpo, 0);
    s = format (s, "  %U\n", format_dpo_id, &rx->dpo, 0);
  }

  return (s);
}

void
ip_punt_redirect_walk (fib_protocol_t fproto,
		       ip_punt_redirect_walk_cb_t cb, void *ctx)
{
  ip_punt_redirect_rx_t *rx;
  u32 ii, rx_sw_if_index;
  index_t *rxs;

  rxs = ip_punt_redirect_cfg.redirect_by_rx_sw_if_index[fproto];

  vec_foreach_index (ii, rxs)
  {
    if (INDEX_INVALID == rxs[ii])
      continue;

    rx = ip_punt_redirect_get (rxs[ii]);

    rx_sw_if_index = (ii == 0 ? ~0 : ii);
    cb (rx_sw_if_index, rx, ctx);
  }
}

static fib_node_t *
ip_punt_redirect_get_node (fib_node_index_t index)
{
  ip_punt_redirect_rx_t *ipr = ip_punt_redirect_get (index);
  return (&(ipr->node));
}

static ip_punt_redirect_rx_t *
ip_punt_redirect_get_from_node (fib_node_t * node)
{
  return ((ip_punt_redirect_rx_t *) (((char *) node) -
				     STRUCT_OFFSET_OF (ip_punt_redirect_rx_t,
						       node)));
}

static void
ip_punt_redirect_last_lock_gone (fib_node_t * node)
{
  /*
   * the lifetime of the entry is managed by the table.
   */
  ASSERT (0);
}

/*
 * A back walk has reached this BIER entry
 */
static fib_node_back_walk_rc_t
ip_punt_redirect_back_walk_notify (fib_node_t * node,
				   fib_node_back_walk_ctx_t * ctx)
{
  /*
   * re-populate the ECMP tables with new choices
   */
  ip_punt_redirect_rx_t *ipr = ip_punt_redirect_get_from_node (node);

  ip_punt_redirect_stack (ipr);

  /*
   * no need to propagate further up the graph, since there's nothing there
   */
  return (FIB_NODE_BACK_WALK_CONTINUE);
}

/*
 * The BIER fmask's graph node virtual function table
 */
static const fib_node_vft_t ip_punt_redirect_vft = {
  .fnv_get = ip_punt_redirect_get_node,
  .fnv_last_lock = ip_punt_redirect_last_lock_gone,
  .fnv_back_walk = ip_punt_redirect_back_walk_notify,
};

static clib_error_t *
ip_punt_drop_init (vlib_main_t * vm)
{
  fib_node_register_type (FIB_NODE_TYPE_IP_PUNT_REDIRECT,
			  &ip_punt_redirect_vft);

  return (NULL);
}

VLIB_INIT_FUNCTION (ip_punt_drop_init);

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