/* Index into FIB vector. */
u32 index;
-
- /* flow hash configuration */
- flow_hash_config_t flow_hash_config;
} ip6_fib_t;
typedef struct ip6_mfib_t
/* Pool of FIBs. */
struct fib_table_t_ *fibs;
+ /* Pool of V6 FIBs. */
+ ip6_fib_t *v6_fibs;
+
/** Vector of MFIBs. */
struct mfib_table_t_ *mfibs;
extern vlib_node_registration_t ip6_glean_node;
extern vlib_node_registration_t ip6_midchain_node;
-extern vlib_node_registration_t ip6_icmp_neighbor_discovery_event_node;
-
-/* ipv6 neighbor discovery - timer/event types */
-typedef enum
-{
- ICMP6_ND_EVENT_INIT,
-} ip6_icmp_neighbor_discovery_event_type_t;
-
-typedef union
-{
- u32 add_del_swindex;
- struct
- {
- u32 up_down_swindex;
- u32 fib_index;
- } up_down_event;
-} ip6_icmp_neighbor_discovery_event_data_t;
-
always_inline uword
ip6_destination_matches_route (const ip6_main_t * im,
const ip6_address_t * key,
clib_error_t *ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst,
u32 sw_if_index);
-clib_error_t *ip6_set_neighbor_limit (u32 neighbor_limit);
-
uword
ip6_udp_register_listener (vlib_main_t * vm,
u16 dst_port, u32 next_node_index);
void ip6_ethernet_update_adjacency (vnet_main_t * vnm,
u32 sw_if_index, u32 ai);
-int
-vnet_set_ip6_ethernet_neighbor (vlib_main_t * vm,
- u32 sw_if_index,
- ip6_address_t * a,
- u8 * link_layer_address,
- uword n_bytes_link_layer_address,
- int is_static);
-int
-vnet_unset_ip6_ethernet_neighbor (vlib_main_t * vm,
- u32 sw_if_index,
- ip6_address_t * a,
- u8 * link_layer_address,
- uword n_bytes_link_layer_address);
void
ip6_link_local_address_from_ethernet_mac_address (ip6_address_t * ip,
int vnet_set_ip6_flow_hash (u32 table_id,
flow_hash_config_t flow_hash_config);
-int
-ip6_neighbor_ra_config (vlib_main_t * vm, u32 sw_if_index,
- u8 suppress, u8 managed, u8 other,
- u8 ll_option, u8 send_unicast, u8 cease,
- u8 use_lifetime, u32 lifetime,
- u32 initial_count, u32 initial_interval,
- u32 max_interval, u32 min_interval, u8 is_no);
-
-int
-ip6_neighbor_ra_prefix (vlib_main_t * vm, u32 sw_if_index,
- ip6_address_t * prefix_addr, u8 prefix_len,
- u8 use_default, u32 val_lifetime, u32 pref_lifetime,
- u8 no_advertise, u8 off_link, u8 no_autoconfig,
- u8 no_onlink, u8 is_no);
-
-
clib_error_t *enable_ip6_interface (vlib_main_t * vm, u32 sw_if_index);
clib_error_t *disable_ip6_interface (vlib_main_t * vm, u32 sw_if_index);
u32 sw_if_index,
ip6_address_t * address);
-void vnet_register_ip6_neighbor_resolution_event (vnet_main_t * vnm,
- void *address_arg,
- uword node_index,
- uword type_opaque,
- uword data);
-
int vnet_add_del_ip6_nd_change_event (vnet_main_t * vnm,
void *data_callback,
u32 pid,
vlib_node_runtime_t * node,
vlib_buffer_t * p0,
ethernet_header_t * eth,
- ip6_header_t * ip,
- u32 sw_if_index, u16 bd_index, u8 shg);
+ ip6_header_t * ip, u32 sw_if_index, u16 bd_index);
+
+void send_ip6_na (vlib_main_t * vm, vnet_hw_interface_t * hi);
u8 *format_ip6_forward_next_trace (u8 * s, va_list * args);
ip6_compute_flow_hash (const ip6_header_t * ip,
flow_hash_config_t flow_hash_config)
{
- tcp_header_t *tcp = (void *) (ip + 1);
+ tcp_header_t *tcp;
u64 a, b, c;
u64 t1, t2;
- uword is_tcp_udp = (ip->protocol == IP_PROTOCOL_TCP
- || ip->protocol == IP_PROTOCOL_UDP);
+ uword is_tcp_udp = 0;
+ u8 protocol = ip->protocol;
+
+ if (PREDICT_TRUE
+ ((ip->protocol == IP_PROTOCOL_TCP)
+ || (ip->protocol == IP_PROTOCOL_UDP)))
+ {
+ is_tcp_udp = 1;
+ tcp = (void *) (ip + 1);
+ }
+ else if (ip->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
+ {
+ ip6_hop_by_hop_header_t *hbh = (ip6_hop_by_hop_header_t *) (ip + 1);
+ if ((hbh->protocol == IP_PROTOCOL_TCP) ||
+ (hbh->protocol == IP_PROTOCOL_UDP))
+ {
+ is_tcp_udp = 1;
+ tcp = (tcp_header_t *) ((u8 *) hbh + ((hbh->length + 1) << 3));
+ }
+ protocol = hbh->protocol;
+ }
t1 = (ip->src_address.as_u64[0] ^ ip->src_address.as_u64[1]);
t1 = (flow_hash_config & IP_FLOW_HASH_SRC_ADDR) ? t1 : 0;
a = (flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ? t2 : t1;
b = (flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ? t1 : t2;
- b ^= (flow_hash_config & IP_FLOW_HASH_PROTO) ? ip->protocol : 0;
+ b ^= (flow_hash_config & IP_FLOW_HASH_PROTO) ? protocol : 0;
- t1 = is_tcp_udp ? tcp->ports.src : 0;
- t2 = is_tcp_udp ? tcp->ports.dst : 0;
+ t1 = is_tcp_udp ? tcp->src : 0;
+ t2 = is_tcp_udp ? tcp->dst : 0;
t1 = (flow_hash_config & IP_FLOW_HASH_SRC_PORT) ? t1 : 0;
t2 = (flow_hash_config & IP_FLOW_HASH_DST_PORT) ? t2 : 0;
return (u32) c;
}
+/* ip6_locate_header
+ *
+ * This function is to search for the header specified by the protocol number
+ * in find_hdr_type.
+ * This is used to locate a specific IPv6 extension header
+ * or to find transport layer header.
+ * 1. If the find_hdr_type < 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_type > 0 protocol number is found then the
+ * offset is stored in *offset and protocol number of the header is
+ * returned.
+ * 3. If find_hdr_type 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_type, 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_type);
+ 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_type < 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);
+}
+
+u8 *format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args);
/*
* Hop-by-Hop handling
*/
int ip6_hbh_unregister_option (u8 option);
void ip6_hbh_set_next_override (uword next);
+/**
+ * Push IPv6 header to buffer
+ *
+ * @param vm - vlib_main
+ * @param b - buffer to write the header to
+ * @param src - source IP
+ * @param dst - destination IP
+ * @param prot - payload proto
+ *
+ * @return - pointer to start of IP header
+ */
+always_inline void *
+vlib_buffer_push_ip6 (vlib_main_t * vm, vlib_buffer_t * b,
+ ip6_address_t * src, ip6_address_t * dst, int proto)
+{
+ ip6_header_t *ip6h;
+ u16 payload_length;
+
+ /* make some room */
+ ip6h = vlib_buffer_push_uninit (b, sizeof (ip6_header_t));
+
+ ip6h->ip_version_traffic_class_and_flow_label =
+ clib_host_to_net_u32 (0x6 << 28);
+
+ /* calculate ip6 payload length */
+ payload_length = vlib_buffer_length_in_chain (vm, b);
+ payload_length -= sizeof (*ip6h);
+
+ ip6h->payload_length = clib_host_to_net_u16 (payload_length);
+
+ ip6h->hop_limit = 0xff;
+ ip6h->protocol = proto;
+ clib_memcpy (ip6h->src_address.as_u8, src->as_u8,
+ sizeof (ip6h->src_address));
+ clib_memcpy (ip6h->dst_address.as_u8, dst->as_u8,
+ sizeof (ip6h->src_address));
+ b->flags |= VNET_BUFFER_F_IS_IP6;
+
+ return ip6h;
+}
+
#endif /* included_ip_ip6_h */
/*