vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters;
u32 n_left_from, n_left_to_next, *from, *to_next;
ip_lookup_next_t next;
- u32 cpu_index = os_get_cpu_number ();
+ u32 thread_index = vlib_get_thread_index ();
from = vlib_frame_vector_args (frame);
n_left_from = frame->n_vectors;
vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
vlib_increment_combined_counter
- (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
+ (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
vlib_increment_combined_counter
- (cm, cpu_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
+ (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
from += 2;
to_next += 2;
vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
vlib_increment_combined_counter
- (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
+ (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
from += 1;
to_next += 1;
return;
}
- if (sw_if_index != 0)
- ip6_mfib_interface_enable_disable (sw_if_index, is_enable);
-
vnet_feature_enable_disable ("ip6-unicast", "ip6-lookup", sw_if_index,
is_enable, 0, 0);
/* get first interface address */
ip6_address_t *
-ip6_interface_first_address (ip6_main_t * im,
- u32 sw_if_index,
- ip_interface_address_t ** result_ia)
+ip6_interface_first_address (ip6_main_t * im, u32 sw_if_index)
{
ip_lookup_main_t *lm = &im->lookup_main;
ip_interface_address_t *ia = 0;
break;
}));
/* *INDENT-ON* */
- if (result_ia)
- *result_ia = result ? ia : 0;
return result;
}
vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
u32 n_left_from, n_left_to_next, *from, *to_next;
ip_lookup_next_t next;
- u32 cpu_index = os_get_cpu_number ();
+ u32 thread_index = vlib_get_thread_index ();
ip6_main_t *im = &ip6_main;
from = vlib_frame_vector_args (frame);
* We don't want to use the same hash value at each level in the recursion
* graph as that would lead to polarisation
*/
- hc0 = vnet_buffer (p0)->ip.flow_hash = 0;
- hc1 = vnet_buffer (p1)->ip.flow_hash = 0;
+ hc0 = hc1 = 0;
if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
{
else
{
hc0 = vnet_buffer (p0)->ip.flow_hash =
- ip6_compute_flow_hash (ip0, hc0);
+ ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
}
}
if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
else
{
hc1 = vnet_buffer (p1)->ip.flow_hash =
- ip6_compute_flow_hash (ip1, hc1);
+ ip6_compute_flow_hash (ip1, lb1->lb_hash_config);
}
}
vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
vlib_increment_combined_counter
- (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
+ (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
vlib_increment_combined_counter
- (cm, cpu_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
+ (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
vlib_validate_buffer_enqueue_x2 (vm, node, next,
to_next, n_left_to_next,
lb0 = load_balance_get (lbi0);
- hc0 = vnet_buffer (p0)->ip.flow_hash = 0;
+ hc0 = 0;
if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
{
if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
else
{
hc0 = vnet_buffer (p0)->ip.flow_hash =
- ip6_compute_flow_hash (ip0, hc0);
+ ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
}
}
dpo0 =
}
vlib_increment_combined_counter
- (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
+ (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
vlib_validate_buffer_enqueue_x1 (vm, node, next,
to_next, n_left_to_next,
CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
- vnet_main_t *vnm = vnet_get_main ();
uword indent = format_get_indent (s);
s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
s = format (s, "\n%U%U",
format_white_space, indent,
format_ip_adjacency_packet_data,
- vnm, t->adj_index, t->packet_data, sizeof (t->packet_data));
+ t->adj_index, t->packet_data, sizeof (t->packet_data));
return s;
}
uword));
}
- /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets) */
+ /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets)
+ * or UDP-Ping packets */
if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
{
u32 skip_bytes;
(ip6_hop_by_hop_ext_t *) data_this_buffer;
/* validate really icmp6 next */
- ASSERT (ext_hdr->next_hdr == IP_PROTOCOL_ICMP6);
+ ASSERT ((ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
+ || (ext_hdr->next_hdr == IP_PROTOCOL_UDP));
skip_bytes = 8 * (1 + ext_hdr->n_data_u64s);
data_this_buffer = (void *) ((u8 *) data_this_buffer + skip_bytes);
return p0->flags;
}
-/* ip6_locate_header
- *
- * This function is to search for the header specified by the find_hdr number.
- * 1. If the find_hdr < 0 then it finds and returns the protocol number and
- * offset stored in *offset of the transport or ESP header in the chain if
- * found.
- * 2. If a header with find_hdr > 0 protocol number is found then the
- * offset is stored in *offset and protocol number of the header is
- * returned.
- * 3. If find_hdr header is not found or packet is malformed or
- * it is a non-first fragment -1 is returned.
- */
-always_inline int
-ip6_locate_header (vlib_buffer_t * p0,
- ip6_header_t * ip0, int find_hdr, u32 * offset)
-{
- u8 next_proto = ip0->protocol;
- u8 *next_header;
- u8 done = 0;
- u32 cur_offset;
- u8 *temp_nxthdr = 0;
- u32 exthdr_len = 0;
-
- next_header = ip6_next_header (ip0);
- cur_offset = sizeof (ip6_header_t);
- while (1)
- {
- done = (next_proto == find_hdr);
- if (PREDICT_FALSE
- (next_header >=
- (u8 *) vlib_buffer_get_current (p0) + p0->current_length))
- {
- //A malicious packet could set an extension header with a too big size
- return (-1);
- }
- if (done)
- break;
- if ((!ip6_ext_hdr (next_proto)) || next_proto == IP_PROTOCOL_IP6_NONXT)
- {
- if (find_hdr < 0)
- break;
- return -1;
- }
- if (next_proto == IP_PROTOCOL_IPV6_FRAGMENTATION)
- {
- ip6_frag_hdr_t *frag_hdr = (ip6_frag_hdr_t *) next_header;
- u16 frag_off = ip6_frag_hdr_offset (frag_hdr);
- /* Non first fragment return -1 */
- if (frag_off)
- return (-1);
- exthdr_len = sizeof (ip6_frag_hdr_t);
- temp_nxthdr = next_header + exthdr_len;
- }
- else if (next_proto == IP_PROTOCOL_IPSEC_AH)
- {
- exthdr_len =
- ip6_ext_authhdr_len (((ip6_ext_header_t *) next_header));
- temp_nxthdr = next_header + exthdr_len;
- }
- else
- {
- exthdr_len =
- ip6_ext_header_len (((ip6_ext_header_t *) next_header));
- temp_nxthdr = next_header + exthdr_len;
- }
- next_proto = ((ip6_ext_header_t *) next_header)->next_hdr;
- next_header = temp_nxthdr;
- cur_offset += exthdr_len;
- }
-
- *offset = cur_offset;
- return (next_proto);
-}
-
/**
* @brief returns number of links on which src is reachable.
*/
len_diff0 = 0;
len_diff1 = 0;
- /* Skip HBH local processing */
- if (PREDICT_FALSE
- (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
- {
- ip6_hop_by_hop_ext_t *ext_hdr =
- (ip6_hop_by_hop_ext_t *) ip6_next_header (ip0);
- next0 = lm->local_next_by_ip_protocol[ext_hdr->next_hdr];
- type0 = lm->builtin_protocol_by_ip_protocol[ext_hdr->next_hdr];
- }
- if (PREDICT_FALSE
- (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
- {
- ip6_hop_by_hop_ext_t *ext_hdr =
- (ip6_hop_by_hop_ext_t *) ip6_next_header (ip1);
- next1 = lm->local_next_by_ip_protocol[ext_hdr->next_hdr];
- type1 = lm->builtin_protocol_by_ip_protocol[ext_hdr->next_hdr];
- }
if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p0, ip0,
IP_PROTOCOL_UDP,
&udp_offset0)))
good_l4_checksum0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
len_diff0 = 0;
- /* Skip HBH local processing */
- if (PREDICT_FALSE
- (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
- {
- ip6_hop_by_hop_ext_t *ext_hdr =
- (ip6_hop_by_hop_ext_t *) ip6_next_header (ip0);
- next0 = lm->local_next_by_ip_protocol[ext_hdr->next_hdr];
- type0 = lm->builtin_protocol_by_ip_protocol[ext_hdr->next_hdr];
- }
if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p0, ip0,
IP_PROTOCOL_UDP,
&udp_offset0)))
always_inline uword
ip6_rewrite_inline (vlib_main_t * vm,
vlib_node_runtime_t * node,
- vlib_frame_t * frame, int is_midchain, int is_mcast)
+ vlib_frame_t * frame,
+ int do_counters, int is_midchain, int is_mcast)
{
ip_lookup_main_t *lm = &ip6_main.lookup_main;
u32 *from = vlib_frame_vector_args (frame);
n_left_from = frame->n_vectors;
next_index = node->cached_next_index;
- u32 cpu_index = os_get_cpu_number ();
+ u32 thread_index = vlib_get_thread_index ();
while (n_left_from > 0)
{
adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
- /* We should never rewrite a pkt using the MISS adjacency */
- ASSERT (adj_index0 && adj_index1);
-
ip0 = vlib_buffer_get_current (p0);
ip1 = vlib_buffer_get_current (p1);
vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
- vlib_increment_combined_counter
- (&adjacency_counters,
- cpu_index,
- adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0);
- vlib_increment_combined_counter
- (&adjacency_counters,
- cpu_index, adj_index1,
- 1, vlib_buffer_length_in_chain (vm, p1) + rw_len1);
+ if (do_counters)
+ {
+ vlib_increment_combined_counter
+ (&adjacency_counters,
+ thread_index, adj_index0, 1,
+ vlib_buffer_length_in_chain (vm, p0) + rw_len0);
+ vlib_increment_combined_counter
+ (&adjacency_counters,
+ thread_index, adj_index1, 1,
+ vlib_buffer_length_in_chain (vm, p1) + rw_len1);
+ }
/* Check MTU of outgoing interface. */
error0 =
vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
next0 = adj0[0].rewrite_header.next_index;
- vnet_feature_arc_start (lm->output_feature_arc_index,
- tx_sw_if_index0, &next0, p0);
+ if (PREDICT_FALSE
+ (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
+ vnet_feature_arc_start (lm->output_feature_arc_index,
+ tx_sw_if_index0, &next0, p0);
}
if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
{
vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
next1 = adj1[0].rewrite_header.next_index;
- vnet_feature_arc_start (lm->output_feature_arc_index,
- tx_sw_if_index1, &next1, p1);
+ if (PREDICT_FALSE
+ (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
+ vnet_feature_arc_start (lm->output_feature_arc_index,
+ tx_sw_if_index1, &next1, p1);
}
/* Guess we are only writing on simple Ethernet header. */
/*
* copy bytes from the IP address into the MAC rewrite
*/
- vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0, 0);
- vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1, 0);
+ vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
+ vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
}
vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
- /* We should never rewrite a pkt using the MISS adjacency */
- ASSERT (adj_index0);
-
adj0 = ip_get_adjacency (lm, adj_index0);
ip0 = vlib_buffer_get_current (p0);
rw_len0 = adj0[0].rewrite_header.data_bytes;
vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
- vlib_increment_combined_counter
- (&adjacency_counters,
- cpu_index,
- adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0);
+ if (do_counters)
+ {
+ vlib_increment_combined_counter
+ (&adjacency_counters,
+ thread_index, adj_index0, 1,
+ vlib_buffer_length_in_chain (vm, p0) + rw_len0);
+ }
/* Check MTU of outgoing interface. */
error0 =
vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
next0 = adj0[0].rewrite_header.next_index;
- vnet_feature_arc_start (lm->output_feature_arc_index,
- tx_sw_if_index0, &next0, p0);
+ if (PREDICT_FALSE
+ (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
+ vnet_feature_arc_start (lm->output_feature_arc_index,
+ tx_sw_if_index0, &next0, p0);
}
if (is_midchain)
}
if (is_mcast)
{
- vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0, 0);
+ vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
}
p0->error = error_node->errors[error0];
ip6_rewrite (vlib_main_t * vm,
vlib_node_runtime_t * node, vlib_frame_t * frame)
{
- return ip6_rewrite_inline (vm, node, frame, 0, 0);
+ if (adj_are_counters_enabled ())
+ return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
+ else
+ return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
}
static uword
ip6_rewrite_mcast (vlib_main_t * vm,
vlib_node_runtime_t * node, vlib_frame_t * frame)
{
- return ip6_rewrite_inline (vm, node, frame, 0, 1);
+ if (adj_are_counters_enabled ())
+ return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
+ else
+ return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
}
static uword
ip6_midchain (vlib_main_t * vm,
vlib_node_runtime_t * node, vlib_frame_t * frame)
{
- return ip6_rewrite_inline (vm, node, frame, 1, 0);
+ if (adj_are_counters_enabled ())
+ return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
+ else
+ return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
+}
+
+static uword
+ip6_mcast_midchain (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+ if (adj_are_counters_enabled ())
+ return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
+ else
+ return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
}
/* *INDENT-OFF* */
VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_mcast_node, ip6_rewrite_mcast);
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (ip6_mcast_midchain_node, static) =
+{
+ .function = ip6_mcast_midchain,
+ .name = "ip6-mcast-midchain",
+ .vector_size = sizeof (u32),
+ .format_trace = format_ip6_rewrite_trace,
+ .sibling_of = "ip6-rewrite",
+};
+/* *INDENT-ON* */
+
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_mcast_midchain_node, ip6_mcast_midchain);
+
/*
* Hop-by-Hop handling
*/
#undef _
};
+u8 *
+format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
+{
+ ip6_hop_by_hop_header_t *hbh0 = va_arg (*args, ip6_hop_by_hop_header_t *);
+ int total_len = va_arg (*args, int);
+ ip6_hop_by_hop_option_t *opt0, *limit0;
+ ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
+ u8 type0;
+
+ s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d",
+ hbh0->protocol, (hbh0->length + 1) << 3, total_len);
+
+ opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
+ limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 + total_len);
+
+ while (opt0 < limit0)
+ {
+ type0 = opt0->type;
+ switch (type0)
+ {
+ case 0: /* Pad, just stop */
+ opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0 + 1);
+ break;
+
+ default:
+ if (hm->trace[type0])
+ {
+ s = (*hm->trace[type0]) (s, opt0);
+ }
+ else
+ {
+ s =
+ format (s, "\n unrecognized option %d length %d", type0,
+ opt0->length);
+ }
+ opt0 =
+ (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
+ sizeof (ip6_hop_by_hop_option_t));
+ break;
+ }
+ }
+ return s;
+}
+
static u8 *
format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
{
vlib_cli_command_t * cmd)
{
vnet_main_t *vnm = vnet_get_main ();
+ ip_interface_address_t *ia;
clib_error_t *error = 0;
u32 sw_if_index, table_id;
goto done;
}
+ /*
+ * If the interface already has in IP address, then a change int
+ * VRF is not allowed. The IP address applied must first be removed.
+ * We do not do that automatically here, since VPP has no knowledge
+ * of whether thoses subnets are valid in the destination VRF.
+ */
+ /* *INDENT-OFF* */
+ foreach_ip_interface_address (&ip6_main.lookup_main,
+ ia, sw_if_index,
+ 1 /* honor unnumbered */,
+ ({
+ ip4_address_t * a;
+
+ a = ip_interface_address_get_address (&ip6_main.lookup_main, ia);
+ error = clib_error_return (0, "interface %U has address %U",
+ format_vnet_sw_if_index_name, vnm,
+ sw_if_index,
+ format_ip6_address, a);
+ goto done;
+ }));
+ /* *INDENT-ON* */
+
{
u32 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
table_id);
* an IP Address is assigned to an interface in the table (which adds a route
* automatically).
*
- * @note IP addresses added after setting the interface IP table end up in
- * the indicated FIB table. If the IP address is added prior to adding the
- * interface to the FIB table, it will NOT be part of the FIB table. Predictable
- * but potentially counter-intuitive results occur if you provision interface
- * addresses in multiple FIBs. Upon RX, packets will be processed in the last
- * IP table ID provisioned. It might be marginally useful to evade source RPF
- * drops to put an interface address into multiple FIBs.
+ * @note IP addresses added after setting the interface IP table are added to
+ * the indicated FIB table. If an IP address is added prior to changing the
+ * table then this is an error. The control plane must remove these addresses
+ * first and then change the table. VPP will not automatically move the
+ * addresses from the old to the new table as it does not know the validity
+ * of such a change.
*
* @cliexpar
* Example of how to add an interface to an IPv6 FIB table (where 2 is the table-id):
vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
- if_addr = ip6_interface_first_address (ipm, sw_if_index, NULL);
+ if_addr = ip6_interface_first_address (ipm, sw_if_index);
if (NULL != if_addr)
{