Support IETF routing Yang models (VPP-503). 02/3502/5
authorNeale Ranns <nranns@cisco.com>
Thu, 20 Oct 2016 12:39:34 +0000 (13:39 +0100)
committerDamjan Marion <dmarion.lists@gmail.com>
Tue, 25 Oct 2016 15:09:10 +0000 (15:09 +0000)
Add support for special routes to send ICMP unreachable or admin prohibited.

Change-Id: Ia1ac65b0e5e925c0f9ebc7824141833b4e18f05e
Signed-off-by: Neale Ranns <nranns@cisco.com>
32 files changed:
plugins/ila-plugin/ila/ila.c
plugins/lb-plugin/lb/lb.c
plugins/sixrd-plugin/sixrd/sixrd.c
vnet/Makefile.am
vnet/vnet/dpo/dpo.c
vnet/vnet/dpo/dpo.h
vnet/vnet/dpo/drop_dpo.h
vnet/vnet/dpo/ip_null_dpo.c [new file with mode: 0644]
vnet/vnet/dpo/ip_null_dpo.h [new file with mode: 0644]
vnet/vnet/fib/fib_entry.c
vnet/vnet/fib/fib_entry.h
vnet/vnet/fib/fib_entry_src.c
vnet/vnet/fib/fib_entry_src.h
vnet/vnet/fib/fib_entry_src_mpls.c
vnet/vnet/fib/fib_path.c
vnet/vnet/fib/fib_path_ext.c
vnet/vnet/fib/fib_table.c
vnet/vnet/fib/fib_table.h
vnet/vnet/fib/fib_test.c
vnet/vnet/fib/mpls_fib.c
vnet/vnet/ip/ip4_forward.c
vnet/vnet/ip/ip4_source_and_port_range_check.c
vnet/vnet/ip/ip6_forward.c
vnet/vnet/ip/lookup.c
vnet/vnet/lisp-gpe/lisp_gpe_adjacency.c
vnet/vnet/lisp-gpe/lisp_gpe_fwd_entry.c
vnet/vnet/map/map.c
vnet/vnet/mpls/interface.c
vnet/vnet/sr/sr.c
vpp-api-test/vat/api_format.c
vpp/vpp-api/api.c
vpp/vpp-api/vpe.api

index 029dd21..90dde5f 100644 (file)
@@ -752,7 +752,7 @@ ila_add_del_entry (ila_add_del_entry_args_t * args)
          /*
           * Create a route that results in the ILA entry
           */
-         dpo_id_t dpo = DPO_NULL;
+         dpo_id_t dpo = DPO_INVALID;
          fib_prefix_t pfx = {
              .fp_addr = {
                  .ip6 = e->ila_address,
index 69bd660..1d9b987 100644 (file)
@@ -594,7 +594,7 @@ int lb_vip_del_ass(u32 vip_index, ip46_address_t *addresses, u32 n)
 static void lb_vip_add_adjacency(lb_main_t *lbm, lb_vip_t *vip)
 {
   dpo_proto_t proto = 0;
-  dpo_id_t dpo = DPO_NULL;
+  dpo_id_t dpo = DPO_INVALID;
   fib_prefix_t pfx = {};
   if (lb_vip_is_ip4(vip)) {
       pfx.fp_addr.ip4 = vip->prefix.ip4;
index 65d353a..cdc0c88 100644 (file)
@@ -40,7 +40,7 @@ sixrd_create_domain (ip6_address_t *ip6_prefix,
                     u32 *sixrd_domain_index,
                     u16 mtu)
 {
-  dpo_id_t dpo_v6 = DPO_NULL, dpo_v4 = DPO_NULL;
+  dpo_id_t dpo_v6 = DPO_INVALID, dpo_v4 = DPO_INVALID;
   sixrd_main_t *mm = &sixrd_main;
   fib_node_index_t fei;
   sixrd_domain_t *d;
@@ -94,7 +94,7 @@ sixrd_create_domain (ip6_address_t *ip6_prefix,
 
   if (FIB_NODE_INDEX_INVALID != fei)
   {
-      dpo_id_t dpo = DPO_NULL;
+      dpo_id_t dpo = DPO_INVALID;
 
       if (fib_entry_get_dpo_for_source (fei, FIB_SOURCE_SIXRD, &dpo))
       {
index bff8418..56baf40 100644 (file)
@@ -805,6 +805,7 @@ nobase_include_HEADERS +=                   \
 libvnet_la_SOURCES +=                          \
   vnet/dpo/dpo.c                                \
   vnet/dpo/drop_dpo.c                           \
+  vnet/dpo/ip_null_dpo.c                        \
   vnet/dpo/punt_dpo.c                           \
   vnet/dpo/receive_dpo.c                        \
   vnet/dpo/load_balance.c                      \
@@ -820,6 +821,7 @@ nobase_include_HEADERS +=                   \
   vnet/dpo/punt_dpo.h                           \
   vnet/dpo/classify_dpo.h                       \
   vnet/dpo/receive_dpo.h                        \
+  vnet/dpo/ip_null_dpo.h                        \
   vnet/dpo/dpo.h
 
 ########################################
index 9f09dff..efee6d6 100644 (file)
@@ -35,6 +35,7 @@
 #include <vnet/dpo/receive_dpo.h>
 #include <vnet/dpo/punt_dpo.h>
 #include <vnet/dpo/classify_dpo.h>
+#include <vnet/dpo/ip_null_dpo.h>
 
 /**
  * Array of char* names for the DPO types and protos
@@ -342,7 +343,7 @@ dpo_stack_i (u32 edge,
      * in order to get an atomic update of the parent we create a temporary,
      * from a copy of the child, and add the next_node. then we copy to the parent
      */
-    dpo_id_t tmp = DPO_NULL;
+    dpo_id_t tmp = DPO_INVALID;
     dpo_copy(&tmp, parent);
 
     /*
@@ -417,6 +418,7 @@ dpo_module_init (vlib_main_t * vm)
     mpls_label_dpo_module_init();
     classify_dpo_module_init();
     lookup_dpo_module_init();
+    ip_null_dpo_module_init();
 
     return (NULL);
 }
index 7ba4756..2ab936e 100644 (file)
@@ -94,6 +94,7 @@ typedef enum dpo_type_t_ {
      */
     DPO_FIRST,
     DPO_DROP,
+    DPO_IP_NULL,
     DPO_PUNT,
     /**
      * @brief load-balancing over a choice of [un]equal cost paths
@@ -116,6 +117,7 @@ typedef enum dpo_type_t_ {
 #define DPO_TYPES {                    \
     [DPO_FIRST] = "dpo-invalid",       \
     [DPO_DROP] = "dpo-drop",   \
+    [DPO_IP_NULL] = "dpo-ip-null",             \
     [DPO_PUNT] = "dpo-punt",   \
     [DPO_ADJACENCY] = "dpo-adjacency", \
     [DPO_ADJACENCY_INCOMPLETE] = "dpo-adjacency-incomplete",   \
@@ -126,7 +128,7 @@ typedef enum dpo_type_t_ {
     [DPO_LOAD_BALANCE] = "dpo-load-balance",   \
     [DPO_LISP_CP] = "dpo-lisp-cp",     \
     [DPO_CLASSIFY] = "dpo-classify",   \
-    [DPO_MPLS_LABEL] = "dpo-mpls-label",       \
+    [DPO_MPLS_LABEL] = "dpo-mpls-label"        \
 }
 
 /**
@@ -159,7 +161,7 @@ _Static_assert(sizeof(dpo_id_t) <= sizeof(u64),
 /**
  * @brief An initialiser for DPos declared on the stack.
  */
-#define DPO_NULL {0}
+#define DPO_INVALID {0}
 
 /**
  * @brief Return true if the DPO object is valid, i.e. has been initialised.
index e7bd8f5..436df36 100644 (file)
  * limitations under the License.
  */
 /**
- * @brief
- * A Data-Path Object is an object that represents actions that are
- * applied to packets are they are switched through VPP.
- * 
- * The DPO is a base class that is specialised by other objects to provide
- * concreate actions
- *
- * The VLIB graph nodes are graph of types, the DPO graph is a graph of instances.
+ * @brief The Drop DPO will drop all packets, no questions asked. It is valid
+ * for any packet protocol.
  */
 
 #ifndef __DROP_DPO_H__
diff --git a/vnet/vnet/dpo/ip_null_dpo.c b/vnet/vnet/dpo/ip_null_dpo.c
new file mode 100644 (file)
index 0000000..22682e4
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * 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.
+ */
+/**
+ * @brief
+ * The data-path object representing dropping the packet
+ */
+
+#include <vnet/dpo/ip_null_dpo.h>
+#include <vnet/ip/ip.h>
+
+/**
+ * @brief A representation of the IP_NULL DPO
+ */
+typedef struct ip_null_dpo_t_
+{
+    /**
+     * @brief The action to take on a packet
+     */
+    ip_null_dpo_action_t ind_action;
+    /**
+     * @brief The next VLIB node
+     */
+    u32 ind_next_index;
+    /**
+     * rate limits
+     */
+} ip_null_dpo_t;
+
+/**
+ * @brief the IP_NULL dpos are shared by all routes, hence they are global.
+ * As the neame implies this is only for IP, hence 2.
+ */
+static ip_null_dpo_t ip_null_dpos[2 * IP_NULL_DPO_ACTION_NUM] = {
+    [0] = {
+       /* proto ip4, no action */
+       .ind_action = IP_NULL_ACTION_NONE,
+    },
+    [1] = {
+       /* proto ip4, action send unreach */
+       .ind_action = IP_NULL_ACTION_SEND_ICMP_UNREACH,
+    },
+    [2] = {
+       /* proto ip4, action send unreach */
+       .ind_action = IP_NULL_ACTION_SEND_ICMP_PROHIBIT,
+    },
+    [3] = {
+       /* proto ip6, no action */
+       .ind_action = IP_NULL_ACTION_NONE,
+    },
+    [4] = {
+       /* proto ip6, action send unreach */
+       .ind_action = IP_NULL_ACTION_SEND_ICMP_UNREACH,
+    },
+    [5] = {
+       /* proto ip6, action send unreach */
+       .ind_action = IP_NULL_ACTION_SEND_ICMP_PROHIBIT,
+    },
+};
+
+/**
+ * @brief Action strings
+ */
+const char *ip_null_action_strings[] = IP_NULL_ACTIONS;
+
+void
+ip_null_dpo_add_and_lock (dpo_proto_t proto,
+                         ip_null_dpo_action_t action,
+                         dpo_id_t *dpo)
+{
+    int i;
+
+    ASSERT((proto == DPO_PROTO_IP4) ||
+          (proto == DPO_PROTO_IP6));
+    ASSERT(action < IP_NULL_DPO_ACTION_NUM);
+
+    i = (proto == DPO_PROTO_IP4 ? 0 : 1);
+
+    dpo_set(dpo, DPO_IP_NULL, proto, (i*IP_NULL_DPO_ACTION_NUM) + action);
+}
+
+always_inline const ip_null_dpo_t*
+ip_null_dpo_get (index_t indi)
+{
+    return (&ip_null_dpos[indi]);
+}
+
+static void
+ip_null_dpo_lock (dpo_id_t *dpo)
+{
+    /*
+     * not maintaining a lock count on the ip_null, they are const global and
+     * never die.
+     */
+}
+static void
+ip_null_dpo_unlock (dpo_id_t *dpo)
+{
+}
+
+static u8*
+format_ip_null_dpo (u8 *s, va_list *ap)
+{
+    index_t index = va_arg(*ap, index_t);
+    CLIB_UNUSED(u32 indent) = va_arg(*ap, u32);
+    const ip_null_dpo_t *ind;
+    dpo_proto_t proto;
+
+    ind = ip_null_dpo_get(index);
+    proto = (index < IP_NULL_DPO_ACTION_NUM ? DPO_PROTO_IP4 : DPO_PROTO_IP6);
+
+    return (format(s, "%U-null action:%s",
+                  format_dpo_proto, proto,
+                  ip_null_action_strings[ind->ind_action]));
+}
+
+const static dpo_vft_t ip_null_vft = {
+    .dv_lock   = ip_null_dpo_lock,
+    .dv_unlock = ip_null_dpo_unlock,
+    .dv_format = format_ip_null_dpo,
+};
+
+/**
+ * @brief The per-protocol VLIB graph nodes that are assigned to a ip_null
+ *        object.
+ *
+ * this means that these graph nodes are ones from which a ip_null is the
+ * parent object in the DPO-graph.
+ */
+const static char* const ip4_null_nodes[] =
+{
+    "ip4-null",
+    NULL,
+};
+const static char* const ip6_null_nodes[] =
+{
+    "ip6-null",
+    NULL,
+};
+
+const static char* const * const ip_null_nodes[DPO_PROTO_NUM] =
+{
+    [DPO_PROTO_IP4] = ip4_null_nodes,
+    [DPO_PROTO_IP6] = ip6_null_nodes,
+};
+
+typedef struct ip_null_dpo_trace_t_
+{
+    index_t ind_index;
+} ip_null_dpo_trace_t;
+
+/**
+ * @brief Exit nodes from a IP_NULL
+ */
+typedef enum ip_null_next_t_
+{
+    IP_NULL_NEXT_DROP,
+    IP_NULL_NEXT_ICMP,
+    IP_NULL_NEXT_NUM,
+} ip_null_next_t;
+
+always_inline uword
+ip_null_dpo_switch (vlib_main_t * vm,
+                   vlib_node_runtime_t * node,
+                   vlib_frame_t * frame,
+                   u8 is_ip4)
+{
+    u32 n_left_from, next_index, *from, *to_next;
+    static f64 time_last_seed_change = -1e100;
+    static u32 hash_seeds[3];
+    static uword hash_bitmap[256 / BITS (uword)];
+    f64 time_now;
+
+    from = vlib_frame_vector_args (frame);
+    n_left_from = frame->n_vectors;
+
+    time_now = vlib_time_now (vm);
+    if (time_now - time_last_seed_change > 1e-1)
+    {
+       uword i;
+       u32 * r = clib_random_buffer_get_data (&vm->random_buffer,
+                                              sizeof (hash_seeds));
+       for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
+           hash_seeds[i] = r[i];
+
+       /* Mark all hash keys as been not-seen before. */
+       for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
+           hash_bitmap[i] = 0;
+
+       time_last_seed_change = time_now;
+    }
+
+    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);
+
+       while (n_left_from > 0 && n_left_to_next > 0)
+       {
+           u32 a0, b0, c0, m0, drop0;
+           vlib_buffer_t *p0;
+           u32 bi0, indi0, next0;
+           const ip_null_dpo_t *ind0;
+           uword bm0;
+
+           bi0 = from[0];
+           to_next[0] = bi0;
+           from += 1;
+           to_next += 1;
+           n_left_from -= 1;
+           n_left_to_next -= 1;
+
+           p0 = vlib_get_buffer (vm, bi0);
+
+           /* lookup dst + src mac */
+           indi0 =  vnet_buffer (p0)->ip.adj_index[VLIB_TX];
+           ind0 = ip_null_dpo_get(indi0);
+           next0 = IP_NULL_NEXT_DROP;
+
+           /*
+            * rate limit - don't DoS the sender.
+            */
+           a0 = hash_seeds[0];
+           b0 = hash_seeds[1];
+           c0 = hash_seeds[2];
+
+           if (is_ip4)
+           {
+               ip4_header_t *ip0 = vlib_buffer_get_current (p0);
+
+               a0 ^= ip0->dst_address.data_u32;
+               b0 ^= ip0->src_address.data_u32;
+
+               hash_v3_finalize32 (a0, b0, c0);
+           }
+           else
+           {
+               ip6_header_t *ip0 = vlib_buffer_get_current (p0);
+
+               a0 ^= ip0->dst_address.as_u32[0];
+               b0 ^= ip0->src_address.as_u32[0];
+               c0 ^= ip0->src_address.as_u32[1];
+
+               hash_v3_mix32 (a0, b0, c0);
+
+               a0 ^= ip0->dst_address.as_u32[1];
+               b0 ^= ip0->src_address.as_u32[2];
+               c0 ^= ip0->src_address.as_u32[3];
+
+               hash_v3_finalize32 (a0, b0, c0);
+           }
+
+           c0 &= BITS (hash_bitmap) - 1;
+           c0 = c0 / BITS (uword);
+           m0 = (uword) 1 << (c0 % BITS (uword));
+
+           bm0 = hash_bitmap[c0];
+           drop0 = (bm0 & m0) != 0;
+
+           /* Mark it as seen. */
+           hash_bitmap[c0] = bm0 | m0;
+
+           if (PREDICT_FALSE(!drop0))
+           {
+               if (is_ip4)
+               {
+                   /*
+                    * There's a trade-off here. This conditinal statement
+                    * versus a graph node per-condition. Given the number
+                    * expect number of packets to reach a null route is 0
+                    * we favour the run-time cost over the graph complexity
+                    */
+                   if (IP_NULL_ACTION_SEND_ICMP_UNREACH == ind0->ind_action)
+                   {
+                       next0 = IP_NULL_NEXT_ICMP;
+                       icmp4_error_set_vnet_buffer(
+                           p0,
+                           ICMP4_destination_unreachable,
+                           ICMP4_destination_unreachable_destination_unreachable_host,
+                           0);
+                   }
+                   else if (IP_NULL_ACTION_SEND_ICMP_PROHIBIT == ind0->ind_action)
+                   {
+                       next0 = IP_NULL_NEXT_ICMP;
+                       icmp4_error_set_vnet_buffer(
+                           p0,
+                           ICMP4_destination_unreachable,
+                           ICMP4_destination_unreachable_host_administratively_prohibited,
+                           0);
+                   }
+               }
+               else
+               {
+                   if (IP_NULL_ACTION_SEND_ICMP_UNREACH == ind0->ind_action)
+                   {
+                       next0 = IP_NULL_NEXT_ICMP;
+                       icmp6_error_set_vnet_buffer(
+                           p0,
+                           ICMP6_destination_unreachable,
+                           ICMP6_destination_unreachable_no_route_to_destination,
+                           0);
+                   }
+                   else if (IP_NULL_ACTION_SEND_ICMP_PROHIBIT == ind0->ind_action)
+                   {
+                       next0 = IP_NULL_NEXT_ICMP;
+                       icmp6_error_set_vnet_buffer(
+                           p0,
+                           ICMP6_destination_unreachable,
+                           ICMP6_destination_unreachable_destination_administratively_prohibited,
+                           0);
+                   }
+               }
+           }
+
+           if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
+           {
+               ip_null_dpo_trace_t *tr = vlib_add_trace (vm, node, p0,
+                                                         sizeof (*tr));
+               tr->ind_index = indi0;
+           }
+           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);
+    }
+
+    return frame->n_vectors;
+}
+
+static u8 *
+format_ip_null_dpo_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_null_dpo_trace_t *t = va_arg (*args, ip_null_dpo_trace_t *);
+
+  s = format (s, "%U", format_ip_null_dpo, t->ind_index, 0);
+  return s;
+}
+
+static uword
+ip4_null_dpo_switch (vlib_main_t * vm,
+                   vlib_node_runtime_t * node,
+                   vlib_frame_t * frame)
+{
+    return (ip_null_dpo_switch(vm, node, frame, 1));
+}
+
+/**
+ * @brief
+ */
+VLIB_REGISTER_NODE (ip4_null_dpo_node) = {
+  .function = ip4_null_dpo_switch,
+  .name = "ip4-null",
+  .vector_size = sizeof (u32),
+
+  .format_trace = format_ip_null_dpo_trace,
+  .n_next_nodes = IP_NULL_NEXT_NUM,
+  .next_nodes = {
+      [IP_NULL_NEXT_DROP] = "ip4-drop",
+      [IP_NULL_NEXT_ICMP] = "ip4-icmp-error",
+  },
+};
+
+static uword
+ip6_null_dpo_switch (vlib_main_t * vm,
+                   vlib_node_runtime_t * node,
+                   vlib_frame_t * frame)
+{
+    return (ip_null_dpo_switch(vm, node, frame, 0));
+}
+
+/**
+ * @brief
+ */
+VLIB_REGISTER_NODE (ip6_null_dpo_node) = {
+  .function = ip6_null_dpo_switch,
+  .name = "ip6-null",
+  .vector_size = sizeof (u32),
+
+  .format_trace = format_ip_null_dpo_trace,
+  .n_next_nodes = IP_NULL_NEXT_NUM,
+  .next_nodes = {
+      [IP_NULL_NEXT_DROP] = "ip6-drop",
+      [IP_NULL_NEXT_ICMP] = "ip6-icmp-error",
+  },
+};
+
+void
+ip_null_dpo_module_init (void)
+{
+    dpo_register(DPO_IP_NULL, &ip_null_vft, ip_null_nodes);
+}
diff --git a/vnet/vnet/dpo/ip_null_dpo.h b/vnet/vnet/dpo/ip_null_dpo.h
new file mode 100644 (file)
index 0000000..002a2a7
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+/**
+ * @brief
+ * The IP NULL DPO represents the rubbish bin for IP traffic. Without specifying an
+ * action (i.e. send IMCP type X to sender) it is equivalent to using a drop DPO.
+ * However, in contrast to the drop DPO any route that resovles via a NULL, is
+ * considered to 'resolved' by FIB, i.e. a IP NULL is used when the control plane
+ * is explicitly expressing the desire to drop packets. Drop DPOs are used
+ * internally by FIB when resolution is not possible.
+ *
+ * Any replies to sender are rate limited.
+ */
+
+#ifndef __IP_NULL_DPO_H__
+#define __IP_NULL_DPO_H__
+
+#include <vnet/dpo/dpo.h>
+
+/**
+ * @brief Actions to take when a packet encounters the NULL DPO
+ */
+typedef enum ip_null_dpo_action_t_
+{
+    IP_NULL_ACTION_NONE,
+    IP_NULL_ACTION_SEND_ICMP_UNREACH,
+    IP_NULL_ACTION_SEND_ICMP_PROHIBIT,
+} ip_null_dpo_action_t;
+
+#define IP_NULL_ACTIONS {                                              \
+    [IP_NULL_ACTION_NONE] = "discard",                                 \
+    [IP_NULL_ACTION_SEND_ICMP_UNREACH] = "send-unreachable",           \
+    [IP_NULL_ACTION_SEND_ICMP_PROHIBIT] = "send-prohibited",           \
+}
+
+#define IP_NULL_DPO_ACTION_NUM (IP_NULL_ACTION_SEND_ICMP_PROHIBIT+1)
+
+extern void ip_null_dpo_add_and_lock (dpo_proto_t proto,
+                                     ip_null_dpo_action_t action,
+                                     dpo_id_t *dpo);
+
+extern void ip_null_dpo_module_init(void);
+
+#endif
index 404f0f4..1047c50 100644 (file)
@@ -753,39 +753,26 @@ fib_entry_post_update_actions (fib_entry_t *fib_entry,
     fib_entry_post_install_actions(fib_entry, source, old_flags);
 }
 
-void
-fib_entry_special_add (fib_node_index_t fib_entry_index,
-                      fib_source_t source,
-                      fib_entry_flag_t flags,
-                      const dpo_id_t *dpo)
+static void
+fib_entry_source_change (fib_entry_t *fib_entry,
+                        fib_source_t best_source,
+                        fib_source_t new_source,
+                        fib_entry_flag_t old_flags)
 {
-    fib_source_t best_source;
-    fib_entry_flag_t bflags;
-    fib_entry_t *fib_entry;
-    fib_entry_src_t *bsrc;
-
-    fib_entry = fib_entry_get(fib_entry_index);
-
-    bsrc = fib_entry_get_best_src_i(fib_entry);
-    best_source = fib_entry_src_get_source(bsrc);
-    bflags = fib_entry_src_get_flags(bsrc);
-
-    fib_entry = fib_entry_src_action_add(fib_entry, source, flags, dpo);
-
     /*
      * if the path list for the source passed is invalid,
      * then we need to create a new one. else we are updating
      * an existing.
      */
-    if (source < best_source)
+    if (new_source < best_source)
     {
        /*
         * we have a new winning source.
         */
        fib_entry_src_action_deactivate(fib_entry, best_source);
-       fib_entry_src_action_activate(fib_entry, source);
+       fib_entry_src_action_activate(fib_entry, new_source);
     }
-    else if (source > best_source)
+    else if (new_source > best_source)
     {
        /*
         * the new source loses. nothing to do here.
@@ -800,13 +787,56 @@ fib_entry_special_add (fib_node_index_t fib_entry_index,
         * But the path-list was updated, which will contribute new forwarding,
         * so install it.
         */
-       fib_entry_src_action_deactivate(fib_entry, source);
-       fib_entry_src_action_activate(fib_entry, source);
+       fib_entry_src_action_deactivate(fib_entry, new_source);
+       fib_entry_src_action_activate(fib_entry, new_source);
     }
 
-    fib_entry_post_update_actions(fib_entry, source, bflags);
+    fib_entry_post_update_actions(fib_entry, new_source, old_flags);
+}
+
+void
+fib_entry_special_add (fib_node_index_t fib_entry_index,
+                      fib_source_t source,
+                      fib_entry_flag_t flags,
+                      const dpo_id_t *dpo)
+{
+    fib_source_t best_source;
+    fib_entry_flag_t bflags;
+    fib_entry_t *fib_entry;
+    fib_entry_src_t *bsrc;
+
+    fib_entry = fib_entry_get(fib_entry_index);
+
+    bsrc = fib_entry_get_best_src_i(fib_entry);
+    best_source = fib_entry_src_get_source(bsrc);
+    bflags = fib_entry_src_get_flags(bsrc);
+
+    fib_entry = fib_entry_src_action_add(fib_entry, source, flags, dpo);
+    fib_entry_source_change(fib_entry, best_source, source, bflags);
+}
+
+void
+fib_entry_special_update (fib_node_index_t fib_entry_index,
+                         fib_source_t source,
+                         fib_entry_flag_t flags,
+                         const dpo_id_t *dpo)
+{
+    fib_source_t best_source;
+    fib_entry_flag_t bflags;
+    fib_entry_t *fib_entry;
+    fib_entry_src_t *bsrc;
+
+    fib_entry = fib_entry_get(fib_entry_index);
+
+    bsrc = fib_entry_get_best_src_i(fib_entry);
+    best_source = fib_entry_src_get_source(bsrc);
+    bflags = fib_entry_src_get_flags(bsrc);
+
+    fib_entry = fib_entry_src_action_update(fib_entry, source, flags, dpo);
+    fib_entry_source_change(fib_entry, best_source, source, bflags);
 }
 
+
 void
 fib_entry_path_add (fib_node_index_t fib_entry_index,
                    fib_source_t source,
index bfebe5d..2b7ea63 100644 (file)
@@ -446,6 +446,10 @@ extern void fib_entry_special_add(fib_node_index_t fib_entry_index,
                                  fib_source_t source,
                                  fib_entry_flag_t flags,
                                  const dpo_id_t *dpo);
+extern void fib_entry_special_update(fib_node_index_t fib_entry_index,
+                                    fib_source_t source,
+                                    fib_entry_flag_t flags,
+                                    const dpo_id_t *dpo);
 extern fib_entry_src_flag_t fib_entry_special_remove(fib_node_index_t fib_entry_index,
                                                     fib_source_t source);
 
index 66bb3df..2cbdf18 100644 (file)
@@ -745,6 +745,56 @@ fib_entry_src_action_add (fib_entry_t *fib_entry,
     return (fib_entry);
 }
 
+/*
+ * fib_entry_src_action_update
+ *
+ * Adding a source can result in a new fib_entry being created, which
+ * can inturn mean the pool is realloc'd and thus the entry passed as
+ * an argument it also realloc'd
+ * @return the original entry
+ */
+fib_entry_t *
+fib_entry_src_action_update (fib_entry_t *fib_entry,
+                            fib_source_t source,
+                            fib_entry_flag_t flags,
+                            const dpo_id_t *dpo)
+{
+    fib_node_index_t fib_entry_index, old_path_list_index;
+    fib_entry_src_t *esrc;
+
+    esrc = fib_entry_src_find_or_create(fib_entry, source, NULL);
+
+    if (NULL == esrc)
+       return (fib_entry_src_action_add(fib_entry, source, flags, dpo));
+
+    old_path_list_index = esrc->fes_pl;
+    esrc->fes_entry_flags = flags;
+
+    /*
+     * save variable so we can recover from a fib_entry realloc.
+     */
+    fib_entry_index = fib_entry_get_index(fib_entry);
+
+    if (NULL != fib_entry_src_vft[source].fesv_add)
+    {
+       fib_entry_src_vft[source].fesv_add(esrc,
+                                          fib_entry,
+                                          flags,
+                                          fib_entry_get_proto(fib_entry),
+                                          dpo);
+    }
+
+    fib_entry = fib_entry_get(fib_entry_index);
+
+    esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
+
+    fib_path_list_lock(esrc->fes_pl);
+    fib_path_list_unlock(old_path_list_index);
+
+    return (fib_entry);
+}
+
+
 fib_entry_src_flag_t
 fib_entry_src_action_remove (fib_entry_t *fib_entry,
                             fib_source_t source)
index d70aabc..0b98c1c 100644 (file)
@@ -233,6 +233,10 @@ extern fib_entry_t* fib_entry_src_action_add(fib_entry_t *fib_entry,
                                             fib_source_t source,
                                             fib_entry_flag_t flags,
                                             const dpo_id_t *dpo);
+extern fib_entry_t* fib_entry_src_action_update(fib_entry_t *fib_entry,
+                                               fib_source_t source,
+                                               fib_entry_flag_t flags,
+                                               const dpo_id_t *dpo);
 
 extern fib_entry_src_flag_t fib_entry_src_action_remove(fib_entry_t *fib_entry,
                                                        fib_source_t source);
index 4079d8f..4c316f7 100644 (file)
@@ -104,7 +104,7 @@ fib_entry_src_mpls_set_data (fib_entry_src_t *src,
            .fp_label = label,
        };
        fib_node_index_t fib_index;
-       dpo_id_t dpo = DPO_NULL;
+       dpo_id_t dpo = DPO_INVALID;
 
         /*
          * adding a new local label. make sure the MPLS fib exists.
index b67fedf..e92e233 100644 (file)
@@ -563,7 +563,7 @@ fib_path_recursive_adj_update (fib_path_t *path,
                               fib_forward_chain_type_t fct,
                               dpo_id_t *dpo)
 {
-    dpo_id_t via_dpo = DPO_NULL;
+    dpo_id_t via_dpo = DPO_INVALID;
 
     /*
      * get the DPO to resolve through from the via-entry
index 05e62d9..6603b64 100644 (file)
@@ -135,7 +135,7 @@ fib_path_ext_stack (fib_path_ext_t *path_ext,
        break;
     }
 
-    dpo_id_t via_dpo = DPO_NULL;
+    dpo_id_t via_dpo = DPO_INVALID;
 
     /*
      * The next object in the graph after the imposition of the label
index d293d81..54bc808 100644 (file)
@@ -323,6 +323,48 @@ fib_table_entry_special_dpo_add (u32 fib_index,
     return (fib_entry_index);
 }
 
+fib_node_index_t
+fib_table_entry_special_dpo_update (u32 fib_index,
+                                   const fib_prefix_t *prefix,
+                                   fib_source_t source,
+                                   fib_entry_flag_t flags,
+                                   const dpo_id_t *dpo)
+{
+    fib_node_index_t fib_entry_index;
+    fib_table_t *fib_table;
+
+    fib_table = fib_table_get(fib_index, prefix->fp_proto);
+    fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
+
+    if (FIB_NODE_INDEX_INVALID == fib_entry_index)
+    {
+       fib_entry_index = fib_entry_create_special(fib_index, prefix,
+                                                  source, flags,
+                                                  dpo);
+
+       fib_table_entry_insert(fib_table, prefix, fib_entry_index);
+        fib_table->ft_src_route_counts[source]++;
+    }
+    else
+    {
+        int was_sourced;
+
+        was_sourced = fib_entry_is_sourced(fib_entry_index, source);
+
+       if (was_sourced)
+           fib_entry_special_update(fib_entry_index, source, flags, dpo);
+       else
+           fib_entry_special_add(fib_entry_index, source, flags, dpo);
+
+        if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
+        {
+            fib_table->ft_src_route_counts[source]++;
+        }
+    }
+
+    return (fib_entry_index);
+}
+
 fib_node_index_t
 fib_table_entry_special_add (u32 fib_index,
                             const fib_prefix_t *prefix,
@@ -331,7 +373,7 @@ fib_table_entry_special_add (u32 fib_index,
                             adj_index_t adj_index)
 {
     fib_node_index_t fib_entry_index;
-    dpo_id_t tmp_dpo = DPO_NULL;
+    dpo_id_t tmp_dpo = DPO_INVALID;
 
     if (ADJ_INDEX_INVALID != adj_index)
     {
@@ -353,22 +395,6 @@ fib_table_entry_special_add (u32 fib_index,
     return (fib_entry_index);
 }
 
-void
-fib_table_entry_special_dpo_update (fib_node_index_t fib_entry_index,
-                                   fib_source_t source,
-                                   fib_entry_flag_t flags,
-                                   const dpo_id_t *dpo)
-{
-    fib_prefix_t prefix;
-    u32 fib_index;
-
-    fib_entry_get_prefix(fib_entry_index, &prefix);
-    fib_index = fib_entry_get_fib_index(fib_entry_index);
-
-    fib_table_entry_special_dpo_add(fib_index, &prefix, source, flags, dpo);
-    fib_table_entry_special_remove(fib_index, &prefix, source);
-}
-
 void
 fib_table_entry_special_remove (u32 fib_index,
                                const fib_prefix_t *prefix,
index d7c604f..ef7599a 100644 (file)
@@ -210,9 +210,8 @@ extern fib_node_index_t fib_table_entry_special_dpo_add(u32 fib_index,
  *  Instead the client/source provides the DPO to link to.
  *  Special entries are add/remove reference counted per-source. So n
  * 'removes' are required for n 'adds', if the entry is no longer required.
- *  An 'update' can only be used after an 'add' and is therefore assumed to act
- * on the reference instance of that add (an update is implemented as add/remove
- * pair).
+ *  An 'update' is an 'add' if no 'add' has already been called, otherwise an 'add'
+ * is therefore assumed to act on the reference instance of that add.
  *
  * @param fib_entry_index
  *  The index of the FIB entry to update
@@ -229,10 +228,11 @@ extern fib_node_index_t fib_table_entry_special_dpo_add(u32 fib_index,
  * @return
  *  the index of the fib_entry_t that is created (or existed already).
  */
-extern void fib_table_entry_special_dpo_update (fib_node_index_t fib_entry_index,
-                                               fib_source_t source,
-                                               fib_entry_flag_t stype,
-                                               const dpo_id_t *dpo);
+extern fib_node_index_t fib_table_entry_special_dpo_update (u32 fib_index,
+                                                           const fib_prefix_t *prefix,
+                                                           fib_source_t source,
+                                                           fib_entry_flag_t stype,
+                                                           const dpo_id_t *dpo);
 
 /**
  * @brief
index 9b41795..800f4e6 100644 (file)
@@ -23,6 +23,7 @@
 #include <vnet/dpo/lookup_dpo.h>
 #include <vnet/dpo/drop_dpo.h>
 #include <vnet/dpo/receive_dpo.h>
+#include <vnet/dpo/ip_null_dpo.h>
 
 #include <vnet/mpls/mpls.h>
 
@@ -181,7 +182,7 @@ fib_test_urpf_is_equal (fib_node_index_t fei,
                       fib_forward_chain_type_t fct,
                       u32 num, ...)
 {
-    dpo_id_t dpo = DPO_NULL;
+    dpo_id_t dpo = DPO_INVALID;
     fib_urpf_list_t *urpf;
     index_t ui;
     va_list ap;
@@ -940,7 +941,7 @@ fib_test_v4 (void)
      * An EXCLUSIVE route; one where the user (me) provides the exclusive
      * adjacency through which the route will resovle
      */
-    dpo_id_t ex_dpo = DPO_NULL;
+    dpo_id_t ex_dpo = DPO_INVALID;
 
     lookup_dpo_add_or_lock_w_fib_index(fib_index,
                                        DPO_PROTO_IP4,
@@ -958,6 +959,21 @@ fib_test_v4 (void)
     FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
             "exclusive remote uses lookup DPO");
 
+    /*
+     * update the exclusive to use a different DPO
+     */
+    ip_null_dpo_add_and_lock(FIB_PROTOCOL_IP4,
+                            IP_NULL_ACTION_SEND_ICMP_UNREACH,
+                            &ex_dpo);
+    fib_table_entry_special_dpo_update(fib_index,
+                                      &ex_pfx,
+                                      FIB_SOURCE_SPECIAL,
+                                      FIB_ENTRY_FLAG_EXCLUSIVE,
+                                      &ex_dpo);
+    dpo = fib_entry_contribute_ip_forwarding(fei);
+    FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
+            "exclusive remote uses now uses NULL DPO");
+
     fib_table_entry_special_remove(fib_index,
                                   &ex_pfx,
                                   FIB_SOURCE_SPECIAL);
@@ -1181,7 +1197,7 @@ fib_test_v4 (void)
     /*
      * test the uRPF check functions
      */
-    dpo_id_t dpo_44 = DPO_NULL;
+    dpo_id_t dpo_44 = DPO_INVALID;
     index_t urpfi;
 
     fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
@@ -4822,7 +4838,7 @@ fib_test_validate_entry (fib_node_index_t fei,
                         ...)
 {
     const load_balance_t *lb;
-    dpo_id_t dpo = DPO_NULL;
+    dpo_id_t dpo = DPO_INVALID;
     fib_prefix_t pfx;
     index_t fw_lbi;
     u32 fib_index;
@@ -5214,7 +5230,7 @@ fib_test_label (void)
     /*
      * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
      */
-    dpo_id_t non_eos_1_1_1_1 = DPO_NULL;
+    dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
     fib_entry_contribute_forwarding(fei,
                                    FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
                                    &non_eos_1_1_1_1);
@@ -5273,7 +5289,7 @@ fib_test_label (void)
             "2.2.2.2.2/32 LB 1 buckets via: "
             "label 1600 over 1.1.1.1");
 
-    dpo_id_t dpo_44 = DPO_NULL;
+    dpo_id_t dpo_44 = DPO_INVALID;
     index_t urpfi;
 
     fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
@@ -5339,7 +5355,7 @@ fib_test_label (void)
      * test that the pre-failover load-balance has been in-place
      * modified
      */
-    dpo_id_t current = DPO_NULL;
+    dpo_id_t current = DPO_INVALID;
     fib_entry_contribute_forwarding(fei,
                                    FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
                                    &current);
@@ -5663,7 +5679,7 @@ fib_test_label (void)
             "1.1.1.2/32 LB 1 buckets via: "
             "label 101 over 10.10.10.1");
 
-    dpo_id_t non_eos_1_1_1_2 = DPO_NULL;
+    dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
                                                     &pfx_1_1_1_1_s_32),
                                    FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
@@ -5781,7 +5797,7 @@ fib_test_label (void)
            .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
        },
     };
-    dpo_id_t ip_1_1_1_1 = DPO_NULL;
+    dpo_id_t ip_1_1_1_1 = DPO_INVALID;
 
     fib_table_entry_update_one_path(fib_index,
                                    &pfx_2_2_2_3_s_32,
@@ -6396,7 +6412,7 @@ lfib_test_deagg (void)
     const mpls_label_t deag_label = 50;
     const u32 lfib_index = 0;
     const u32 fib_index = 0;
-    dpo_id_t dpo = DPO_NULL;
+    dpo_id_t dpo = DPO_INVALID;
     const dpo_id_t *dpo1;
     fib_node_index_t lfe;
     lookup_dpo_t *lkd;
index 8f1ccef..6a9b1ac 100644 (file)
@@ -89,7 +89,7 @@ mpls_fib_index_from_table_id (u32 table_id)
 static u32
 mpls_fib_create_with_table_id (u32 table_id)
 {
-    dpo_id_t dpo = DPO_NULL;
+    dpo_id_t dpo = DPO_INVALID;
     fib_table_t *fib_table;
     mpls_eos_bit_t eos;
     mpls_fib_t *mf;
index 9e712f5..bfa9f0a 100644 (file)
@@ -649,7 +649,7 @@ ip4_add_interface_routes (u32 sw_if_index,
          lm->classify_table_index_by_sw_if_index [sw_if_index];
       if (classify_table_index != (u32) ~0)
       {
-          dpo_id_t dpo = DPO_NULL;
+          dpo_id_t dpo = DPO_INVALID;
 
           dpo_set(&dpo,
                   DPO_CLASSIFY,
@@ -1899,10 +1899,6 @@ ip4_arp_inline (vlib_main_t * vm,
          adj0 = ip_get_adjacency (lm, adj_index0);
          ip0 = vlib_buffer_get_current (p0);
 
-         /*
-          * this is the Glean case, so we are ARPing for the
-          * packet's destination
-          */
          a0 = hash_seeds[0];
          b0 = hash_seeds[1];
          c0 = hash_seeds[2];
@@ -1912,6 +1908,10 @@ ip4_arp_inline (vlib_main_t * vm,
 
           if (is_glean)
           {
+             /*
+              * this is the Glean case, so we are ARPing for the
+              * packet's destination
+              */
               a0 ^= ip0->dst_address.data_u32;
           }
           else
@@ -3296,7 +3296,7 @@ int vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
 
       if (table_index != (u32) ~0)
       {
-          dpo_id_t dpo = DPO_NULL;
+          dpo_id_t dpo = DPO_INVALID;
 
           dpo_set(&dpo,
                   DPO_CLASSIFY,
index 677f610..6ee648c 100644 (file)
@@ -955,7 +955,7 @@ add_port_range_adjacency (u32 fib_index,
                          u32 length, u16 * low_ports, u16 * high_ports)
 {
   protocol_port_range_dpo_t *ppr_dpo;
-  dpo_id_t dpop = DPO_NULL;
+  dpo_id_t dpop = DPO_INVALID;
   int i, j, k;
 
   fib_node_index_t fei;
@@ -985,7 +985,7 @@ add_port_range_adjacency (u32 fib_index,
        * the prefix is already there.
        * check it was sourced by us, and if so get the ragne DPO from it.
        */
-      dpo_id_t dpo = DPO_NULL;
+      dpo_id_t dpo = DPO_INVALID;
       const dpo_id_t *bucket;
 
       if (fib_entry_get_dpo_for_source (fei, FIB_SOURCE_SPECIAL, &dpo))
@@ -1045,9 +1045,9 @@ add_port_range_adjacency (u32 fib_index,
     }
   else
     {
-      fib_table_entry_special_dpo_update (fei,
-                                         FIB_SOURCE_SPECIAL,
-                                         FIB_ENTRY_FLAG_NONE, &dpop);
+      fib_entry_special_update (fei,
+                               FIB_SOURCE_SPECIAL,
+                               FIB_ENTRY_FLAG_NONE, &dpop);
     }
 
   return 0;
@@ -1088,7 +1088,7 @@ remove_port_range_adjacency (u32 fib_index,
        * the prefix is already there.
        * check it was sourced by us
        */
-      dpo_id_t dpo = DPO_NULL;
+      dpo_id_t dpo = DPO_INVALID;
       const dpo_id_t *bucket;
 
       if (fib_entry_get_dpo_for_source (fei, FIB_SOURCE_SPECIAL, &dpo))
@@ -1361,7 +1361,7 @@ show_source_and_port_range_check_fn (vlib_main_t * vm,
    * find the longest prefix match on the address requested,
    * check it was sourced by us
    */
-  dpo_id_t dpo = DPO_NULL;
+  dpo_id_t dpo = DPO_INVALID;
   const dpo_id_t *bucket;
 
   if (!fib_entry_get_dpo_for_source (fib_table_lookup (fib_index, &pfx),
index 766b26c..c285af9 100644 (file)
@@ -350,7 +350,7 @@ ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index,
          lm->classify_table_index_by_sw_if_index [sw_if_index];
       if (classify_table_index != (u32) ~0)
       {
-          dpo_id_t dpo = DPO_NULL;
+          dpo_id_t dpo = DPO_INVALID;
 
           dpo_set(&dpo,
                   DPO_CLASSIFY,
@@ -3079,7 +3079,7 @@ int vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
 
       if (table_index != (u32) ~0)
       {
-          dpo_id_t dpo = DPO_NULL;
+          dpo_id_t dpo = DPO_INVALID;
 
           dpo_set(&dpo,
                   DPO_CLASSIFY,
index 1f8735b..78152f0 100644 (file)
@@ -47,6 +47,7 @@
 #include <vnet/dpo/classify_dpo.h>
 #include <vnet/dpo/punt_dpo.h>
 #include <vnet/dpo/receive_dpo.h>
+#include <vnet/dpo/ip_null_dpo.h>
 
 /**
  * @file
@@ -278,6 +279,12 @@ static uword unformat_dpo (unformat_input_t * input, va_list * args)
     dpo_copy(dpo, punt_dpo_get(proto));
   else if (unformat (input, "local"))
     receive_dpo_add_or_lock(proto, ~0, NULL, dpo);
+  else if (unformat (input, "null-send-unreach"))
+      ip_null_dpo_add_and_lock(proto, IP_NULL_ACTION_SEND_ICMP_UNREACH, dpo);
+  else if (unformat (input, "null-send-prohibit"))
+      ip_null_dpo_add_and_lock(proto, IP_NULL_ACTION_SEND_ICMP_PROHIBIT, dpo);
+  else if (unformat (input, "null"))
+      ip_null_dpo_add_and_lock(proto, IP_NULL_ACTION_NONE, dpo);
   else if (unformat (input, "classify"))
     {
       u32 classify_table_index;
@@ -337,7 +344,7 @@ vnet_ip_route_cmd (vlib_main_t * vm,
 {
   unformat_input_t _line_input, * line_input = &_line_input;
   fib_route_path_t *rpaths = NULL, rpath;
-  dpo_id_t dpo = DPO_NULL, *dpos = NULL;
+  dpo_id_t dpo = DPO_INVALID, *dpos = NULL;
   fib_prefix_t *prefixs = NULL, pfx;
   clib_error_t * error = NULL;
   mpls_label_t out_label;
index dadd09d..8c96a25 100644 (file)
@@ -128,7 +128,7 @@ static void
 lisp_gpe_adj_stack_one (lisp_gpe_adjacency_t * ladj, adj_index_t ai)
 {
   const lisp_gpe_tunnel_t *lgt;
-  dpo_id_t tmp = DPO_NULL;
+  dpo_id_t tmp = DPO_INVALID;
 
   lgt = lisp_gpe_tunnel_get (ladj->tunnel_index);
   fib_entry_contribute_forwarding (lgt->fib_entry_index,
index 018fad4..54ee86d 100644 (file)
@@ -61,7 +61,7 @@ ip_dst_fib_add_route (u32 dst_fib_index, const ip_prefix_t * dst_prefix)
   if (dst_fei == FIB_NODE_INDEX_INVALID ||
       NULL == fib_entry_get_source_data (dst_fei, FIB_SOURCE_LISP))
     {
-      dpo_id_t src_lkup_dpo = DPO_NULL;
+      dpo_id_t src_lkup_dpo = DPO_INVALID;
 
       /* create a new src FIB.  */
       src_fib_index =
@@ -274,7 +274,7 @@ create_fib_entries (lisp_gpe_fwd_entry_t * lfe)
 
   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE == lfe->type)
     {
-      dpo_id_t dpo = DPO_NULL;
+      dpo_id_t dpo = DPO_INVALID;
 
       switch (lfe->action)
        {
@@ -659,7 +659,7 @@ static void
 lisp_gpe_l2_update_fwding (lisp_gpe_fwd_entry_t * lfe)
 {
   lisp_gpe_main_t *lgm = &lisp_gpe_main;
-  dpo_id_t dpo = DPO_NULL;
+  dpo_id_t dpo = DPO_INVALID;
 
   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
     {
index 74a9905..beeaf11 100644 (file)
@@ -166,8 +166,8 @@ map_create_domain (ip4_address_t * ip4_prefix,
 {
   u8 suffix_len, suffix_shift;
   map_main_t *mm = &map_main;
-  dpo_id_t dpo_v4 = DPO_NULL;
-  dpo_id_t dpo_v6 = DPO_NULL;
+  dpo_id_t dpo_v4 = DPO_INVALID;
+  dpo_id_t dpo_v6 = DPO_INVALID;
   fib_node_index_t fei;
   map_domain_t *d;
 
@@ -275,7 +275,7 @@ map_create_domain (ip4_address_t * ip4_prefix,
 
   if (FIB_NODE_INDEX_INVALID != fei)
     {
-      dpo_id_t dpo = DPO_NULL;
+      dpo_id_t dpo = DPO_INVALID;
 
       if (fib_entry_get_dpo_for_source (fei, FIB_SOURCE_MAP, &dpo))
        {
index fc297cd..726e672 100644 (file)
@@ -934,7 +934,7 @@ int vnet_mpls_ethernet_add_del_policy_tunnel (u8 *dst,
          .fp_len = tp->mask_width,
          .fp_proto = FIB_PROTOCOL_IP4,
       };
-      dpo_id_t dpo = DPO_NULL;
+      dpo_id_t dpo = DPO_INVALID;
 
       if (is_add)
         {
index 6a78565..287d521 100644 (file)
@@ -834,7 +834,7 @@ ip6_sr_add_del_tunnel (ip6_sr_add_del_tunnel_args_t * a)
   u8 hmac_key_index = 0;
   ip6_sr_policy_t *pt;
   int i;
-  dpo_id_t dpo = DPO_NULL;
+  dpo_id_t dpo = DPO_INVALID;
 
   /* Make sure that the rx FIB exists */
   p = hash_get (im->fib_index_by_table_id, a->rx_table_id);
@@ -1728,7 +1728,7 @@ ip6_sr_add_del_multicastmap (ip6_sr_add_del_multicastmap_args_t * a)
    * We don't handle ugly RFC-related cases yet, but I'm sure PL will complain
    * at some point...
    */
-  dpo_id_t dpo = DPO_NULL;
+  dpo_id_t dpo = DPO_INVALID;
 
   dpo_set (&dpo, sr_dpo_type, DPO_PROTO_IP6, t - sm->tunnels);
 
index 51beada..6f11083 100644 (file)
@@ -5757,6 +5757,7 @@ api_ip_add_del_route (vat_main_t * vam)
   u8 sw_if_index_set = 0;
   u8 is_ipv6 = 0;
   u8 is_local = 0, is_drop = 0;
+  u8 is_unreach = 0, is_prohibit = 0;
   u8 create_vrf_if_needed = 0;
   u8 is_add = 1;
   u8 next_hop_weight = 1;
@@ -5822,6 +5823,14 @@ api_ip_add_del_route (vat_main_t * vam)
        {
          is_drop = 1;
        }
+      else if (unformat (i, "null-send-unreach"))
+       {
+         is_unreach = 1;
+       }
+      else if (unformat (i, "null-send-prohibit"))
+       {
+         is_prohibit = 1;
+       }
       else if (unformat (i, "local"))
        {
          is_local = 1;
@@ -5871,9 +5880,11 @@ api_ip_add_del_route (vat_main_t * vam)
       return -99;
     }
 
-  if (!next_hop_set && !is_drop && !is_local && !is_classify)
+  if (!next_hop_set && !is_drop && !is_local &&
+      !is_classify && !is_unreach && !is_prohibit)
     {
-      errmsg ("next hop / local / drop / classify not set\n");
+      errmsg
+       ("next hop / local / drop / unreach / prohibit / classify not set\n");
       return -99;
     }
 
@@ -5936,6 +5947,8 @@ api_ip_add_del_route (vat_main_t * vam)
 
       mp->is_add = is_add;
       mp->is_drop = is_drop;
+      mp->is_unreach = is_unreach;
+      mp->is_prohibit = is_prohibit;
       mp->is_ipv6 = is_ipv6;
       mp->is_local = is_local;
       mp->is_classify = is_classify;
index cc06740..6ac5109 100644 (file)
 #include <vnet/dpo/receive_dpo.h>
 #include <vnet/dpo/lookup_dpo.h>
 #include <vnet/dpo/classify_dpo.h>
+#include <vnet/dpo/ip_null_dpo.h>
 
 #define f64_endian(a)
 #define f64_print(a,b)
@@ -1032,6 +1033,8 @@ static int
 add_del_route_t_handler (u8 is_multipath,
                         u8 is_add,
                         u8 is_drop,
+                        u8 is_unreach,
+                        u8 is_prohibit,
                         u8 is_local,
                         u8 is_classify,
                         u32 classify_table_index,
@@ -1090,22 +1093,29 @@ add_del_route_t_handler (u8 is_multipath,
 
   dslock (sm, 1 /* release hint */ , 2 /* tag */ );
 
-  if (is_drop || is_local || is_classify)
+  if (is_drop || is_local || is_classify || is_unreach || is_prohibit)
     {
       /*
        * special route types that link directly to the adj
        */
       if (is_add)
        {
-         dpo_id_t dpo = DPO_NULL;
+         dpo_id_t dpo = DPO_INVALID;
          dpo_proto_t dproto;
 
          dproto = fib_proto_to_dpo (prefix->fp_proto);
 
          if (is_drop)
-           dpo_copy (&dpo, drop_dpo_get (dproto));
+           ip_null_dpo_add_and_lock (dproto, IP_NULL_ACTION_NONE, &dpo);
          else if (is_local)
            receive_dpo_add_or_lock (dproto, ~0, NULL, &dpo);
+         else if (is_unreach)
+           ip_null_dpo_add_and_lock (dproto,
+                                     IP_NULL_ACTION_SEND_ICMP_UNREACH, &dpo);
+         else if (is_prohibit)
+           ip_null_dpo_add_and_lock (dproto,
+                                     IP_NULL_ACTION_SEND_ICMP_PROHIBIT,
+                                     &dpo);
          else if (is_classify)
            {
              if (pool_is_free_index (cm->tables,
@@ -1125,10 +1135,10 @@ add_del_route_t_handler (u8 is_multipath,
              return VNET_API_ERROR_NO_SUCH_TABLE;
            }
 
-         fib_table_entry_special_dpo_add (fib_index,
-                                          prefix,
-                                          FIB_SOURCE_API,
-                                          FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
+         fib_table_entry_special_dpo_update (fib_index,
+                                             prefix,
+                                             FIB_SOURCE_API,
+                                             FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
          dpo_reset (&dpo);
        }
       else
@@ -1255,7 +1265,17 @@ ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
   memset (&nh, 0, sizeof (nh));
   memcpy (&nh.ip4, mp->next_hop_address, sizeof (nh.ip4));
 
-  return (add_del_route_t_handler (mp->is_multipath, mp->is_add, mp->is_drop, mp->is_local, mp->is_classify, mp->classify_table_index, mp->is_resolve_host, mp->is_resolve_attached, fib_index, &pfx, 1,       // is_ip4
+  return (add_del_route_t_handler (mp->is_multipath,
+                                  mp->is_add,
+                                  mp->is_drop,
+                                  mp->is_unreach,
+                                  mp->is_prohibit,
+                                  mp->is_local,
+                                  mp->is_classify,
+                                  mp->classify_table_index,
+                                  mp->is_resolve_host,
+                                  mp->is_resolve_attached,
+                                  fib_index, &pfx, 1,
                                   &nh,
                                   ntohl (mp->next_hop_sw_if_index),
                                   next_hop_fib_index,
@@ -1290,7 +1310,17 @@ ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
   memset (&nh, 0, sizeof (nh));
   memcpy (&nh.ip6, mp->next_hop_address, sizeof (nh.ip6));
 
-  return (add_del_route_t_handler (mp->is_multipath, mp->is_add, mp->is_drop, mp->is_local, mp->is_classify, mp->classify_table_index, mp->is_resolve_host, mp->is_resolve_attached, fib_index, &pfx, 0,       // is_ip4
+  return (add_del_route_t_handler (mp->is_multipath,
+                                  mp->is_add,
+                                  mp->is_drop,
+                                  mp->is_unreach,
+                                  mp->is_prohibit,
+                                  mp->is_local,
+                                  mp->is_classify,
+                                  mp->classify_table_index,
+                                  mp->is_resolve_host,
+                                  mp->is_resolve_attached,
+                                  fib_index, &pfx, 0,
                                   &nh, ntohl (mp->next_hop_sw_if_index),
                                   next_hop_fib_index,
                                   mp->next_hop_weight,
@@ -1347,6 +1377,8 @@ mpls_route_add_del_t_handler (vnet_main_t * vnm,
     memcpy (&nh.ip6, mp->mr_next_hop, sizeof (nh.ip6));
 
   return (add_del_route_t_handler (mp->mr_is_multipath, mp->mr_is_add, 0,      // mp->is_drop,
+                                  0,   // mp->is_unreach,
+                                  0,   // mp->is_prohibit,
                                   0,   // mp->is_local,
                                   mp->mr_is_classify,
                                   mp->mr_classify_table_index,
index ac84bdc..c5eacce 100644 (file)
@@ -492,7 +492,9 @@ define mpls_ip_bind_unbind_reply
     @param create_vrf_if_needed - 
     @param resolve_if_needed - 
     @param is_add - 1 if adding the route, 0 if deleting
-    @param is_drop - 
+    @param is_drop - Drop the packet
+    @param is_unreach - Drop the packet and rate limit send ICMP unreachable
+    @param is_prohibit - Drop the packet and rate limit send ICMP prohibited
     @param is_ipv6 - 0 if an ip4 route, else ip6
     @param is_local - 
     @param is_classify - 
@@ -517,6 +519,8 @@ define ip_add_del_route
   u8 resolve_if_needed;
   u8 is_add;
   u8 is_drop;
+  u8 is_unreach;
+  u8 is_prohibit;
   u8 is_ipv6;
   u8 is_local;
   u8 is_classify;