2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <vnet/adj/adj_nbr.h>
17 #include <vnet/adj/adj_internal.h>
18 #include <vnet/ethernet/arp_packet.h>
19 #include <vnet/dpo/drop_dpo.h>
20 #include <vnet/fib/fib_walk.h>
23 adj_get_midchain_node (fib_link_t link)
27 return (ip4_midchain_node.index);
29 return (ip6_midchain_node.index);
31 return (mpls_midchain_node.index);
38 * adj_nbr_midchain_update_rewrite
40 * Update the adjacency's rewrite string. A NULL string implies the
41 * rewrite is reset (i.e. when ARP/ND etnry is gone).
42 * NB: the adj being updated may be handling traffic in the DP.
45 adj_nbr_midchain_update_rewrite (adj_index_t adj_index,
46 u32 post_rewrite_node,
51 ASSERT(ADJ_INDEX_INVALID != adj_index);
53 adj = adj_get(adj_index);
54 adj->lookup_next_index = IP_LOOKUP_NEXT_MIDCHAIN;
55 adj->sub_type.midchain.tx_function_node = post_rewrite_node;
60 * new rewrite provided.
61 * use a dummy rewrite header to get the interface to print into.
64 dpo_id_t tmp = DPO_NULL;
66 vnet_rewrite_for_tunnel(vnet_get_main(),
67 adj->rewrite_header.sw_if_index,
68 adj_get_midchain_node(adj->ia_link),
69 adj->sub_type.midchain.tx_function_node,
70 &dummy.rewrite_header,
75 * this is an update of an existing rewrite.
76 * packets are in flight. we'll need to briefly stack on the drop DPO
77 * whilst the rewrite is written, so any packets that see the partial update
80 if (!dpo_id_is_valid(&adj->sub_type.midchain.next_dpo))
83 * not stacked yet. stack on the drop
85 dpo_stack(DPO_ADJACENCY_MIDCHAIN,
86 fib_proto_to_dpo(adj->ia_nh_proto),
87 &adj->sub_type.midchain.next_dpo,
88 drop_dpo_get(fib_proto_to_dpo(adj->ia_nh_proto)));
91 dpo_copy(&tmp, &adj->sub_type.midchain.next_dpo);
92 dpo_stack(DPO_ADJACENCY_MIDCHAIN,
93 fib_proto_to_dpo(adj->ia_nh_proto),
94 &adj->sub_type.midchain.next_dpo,
95 drop_dpo_get(fib_proto_to_dpo(adj->ia_nh_proto)));
97 CLIB_MEMORY_BARRIER();
99 clib_memcpy(&adj->rewrite_header,
100 &dummy.rewrite_header,
101 VLIB_BUFFER_PRE_DATA_SIZE);
103 CLIB_MEMORY_BARRIER();
106 * The graph arc used/created here is from the post-rewirte node to the
107 * child's registered node. This is because post adj processing the next
108 * node is the interface's specific node, then the post-write-node (aka
109 * the interface's tx-function) - from there we need to get to the stacked
112 dpo_stack_from_node(adj->sub_type.midchain.tx_function_node,
113 &adj->sub_type.midchain.next_dpo,
123 * time for walkies fido.
125 fib_node_back_walk_ctx_t bw_ctx = {
126 .fnbw_reason = FIB_NODE_BW_REASON_ADJ_UPDATE,
129 fib_walk_sync(FIB_NODE_TYPE_ADJ, adj->heap_handle, &bw_ctx);
133 * adj_nbr_midchain_stack
136 adj_nbr_midchain_stack (adj_index_t adj_index,
137 const dpo_id_t *next)
141 ASSERT(ADJ_INDEX_INVALID != adj_index);
143 adj = adj_get(adj_index);
145 ASSERT(IP_LOOKUP_NEXT_MIDCHAIN == adj->lookup_next_index);
147 dpo_stack_from_node(adj->sub_type.midchain.tx_function_node,
148 &adj->sub_type.midchain.next_dpo,
153 format_adj_midchain (u8* s, va_list *ap)
155 index_t index = va_arg(ap, index_t);
156 u32 indent = va_arg(ap, u32);
157 vnet_main_t * vnm = vnet_get_main();
158 ip_adjacency_t * adj = adj_get(index);
160 s = format (s, "%U", format_fib_link, adj->ia_link);
161 s = format (s, " via %U ",
162 format_ip46_address, &adj->sub_type.nbr.next_hop);
163 s = format (s, " %U",
165 vnm->vlib_main, &adj->rewrite_header,
166 sizeof (adj->rewrite_data), indent);
167 s = format (s, "\n%Ustacked-on:\n%U%U",
168 format_white_space, indent,
169 format_white_space, indent+2,
170 format_dpo_id, &adj->sub_type.midchain.next_dpo, indent+2);
176 adj_dpo_lock (dpo_id_t *dpo)
178 adj_lock(dpo->dpoi_index);
181 adj_dpo_unlock (dpo_id_t *dpo)
183 adj_unlock(dpo->dpoi_index);
186 const static dpo_vft_t adj_midchain_dpo_vft = {
187 .dv_lock = adj_dpo_lock,
188 .dv_unlock = adj_dpo_unlock,
189 .dv_format = format_adj_midchain,
193 * @brief The per-protocol VLIB graph nodes that are assigned to a midchain
196 * this means that these graph nodes are ones from which a midchain is the
197 * parent object in the DPO-graph.
199 const static char* const midchain_ip4_nodes[] =
204 const static char* const midchain_ip6_nodes[] =
209 const static char* const midchain_mpls_nodes[] =
215 const static char* const * const midchain_nodes[DPO_PROTO_NUM] =
217 [DPO_PROTO_IP4] = midchain_ip4_nodes,
218 [DPO_PROTO_IP6] = midchain_ip6_nodes,
219 [DPO_PROTO_MPLS] = midchain_mpls_nodes,
223 adj_midchain_module_init (void)
225 dpo_register(DPO_ADJACENCY_MIDCHAIN, &adj_midchain_dpo_vft, midchain_nodes);