#include <vnet/ip/ip.h>
#include <vnet/api_errno.h> /* for API error numbers */
#include <vnet/l2/l2_classify.h> /* for L2_INPUT_CLASSIFY_NEXT_xxx */
+#include <vnet/fib/fib_table.h>
vnet_classify_main_t vnet_classify_main;
vnet_classify_entry_t * e = va_arg (*args, vnet_classify_entry_t *);
s = format
- (s, "[%u]: next_index %d advance %d opaque %d\n",
+ (s, "[%u]: next_index %d advance %d opaque %d action %d metadata %d\n",
vnet_classify_get_offset (t, e), e->next_index, e->advance,
- e->opaque_index);
+ e->opaque_index, e->action, e->metadata);
s = format (s, " k: %U\n", format_hex_bytes, e->key,
u32 next_table_index,
u32 miss_next_index,
u32 * table_index,
+ u8 current_data_flag,
+ i16 current_data_offset,
int is_add)
{
vnet_classify_table_t * t;
if (is_add)
{
- *table_index = ~0;
- if (memory_size == 0)
- return VNET_API_ERROR_INVALID_MEMORY_SIZE;
-
- if (nbuckets == 0)
- return VNET_API_ERROR_INVALID_VALUE;
-
- t = vnet_classify_new_table (cm, mask, nbuckets, memory_size,
- skip, match);
- t->next_table_index = next_table_index;
- t->miss_next_index = miss_next_index;
- *table_index = t - cm->tables;
+ if (*table_index == ~0) /* add */
+ {
+ if (memory_size == 0)
+ return VNET_API_ERROR_INVALID_MEMORY_SIZE;
+
+ if (nbuckets == 0)
+ return VNET_API_ERROR_INVALID_VALUE;
+
+ t = vnet_classify_new_table (cm, mask, nbuckets, memory_size,
+ skip, match);
+ t->next_table_index = next_table_index;
+ t->miss_next_index = miss_next_index;
+ t->current_data_flag = current_data_flag;
+ t->current_data_offset = current_data_offset;
+ *table_index = t - cm->tables;
+ }
+ else /* update */
+ {
+ vnet_classify_main_t *cm = &vnet_classify_main;
+ t = pool_elt_at_index (cm->tables, *table_index);
+
+ t->next_table_index = next_table_index;
+ }
return 0;
}
return 0;
}
+#define foreach_tcp_proto_field \
+_(src_port) \
+_(dst_port)
+
+#define foreach_udp_proto_field \
+_(src_port) \
+_(dst_port)
+
#define foreach_ip4_proto_field \
_(src_address) \
_(dst_address) \
_(protocol) \
_(checksum)
+uword unformat_tcp_mask (unformat_input_t * input, va_list * args)
+{
+ u8 ** maskp = va_arg (*args, u8 **);
+ u8 * mask = 0;
+ u8 found_something = 0;
+ tcp_header_t * tcp;
+
+#define _(a) u8 a=0;
+ foreach_tcp_proto_field;
+#undef _
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (0) ;
+#define _(a) else if (unformat (input, #a)) a=1;
+ foreach_tcp_proto_field
+#undef _
+ else
+ break;
+ }
+
+#define _(a) found_something += a;
+ foreach_tcp_proto_field;
+#undef _
+
+ if (found_something == 0)
+ return 0;
+
+ vec_validate (mask, sizeof (*tcp) - 1);
+
+ tcp = (tcp_header_t *) mask;
+
+#define _(a) if (a) memset (&tcp->a, 0xff, sizeof (tcp->a));
+ foreach_tcp_proto_field;
+#undef _
+
+ *maskp = mask;
+ return 1;
+}
+
+uword unformat_udp_mask (unformat_input_t * input, va_list * args)
+{
+ u8 ** maskp = va_arg (*args, u8 **);
+ u8 * mask = 0;
+ u8 found_something = 0;
+ udp_header_t * udp;
+
+#define _(a) u8 a=0;
+ foreach_udp_proto_field;
+#undef _
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (0) ;
+#define _(a) else if (unformat (input, #a)) a=1;
+ foreach_udp_proto_field
+#undef _
+ else
+ break;
+ }
+
+#define _(a) found_something += a;
+ foreach_udp_proto_field;
+#undef _
+
+ if (found_something == 0)
+ return 0;
+
+ vec_validate (mask, sizeof (*udp) - 1);
+
+ udp = (udp_header_t *) mask;
+
+#define _(a) if (a) memset (&udp->a, 0xff, sizeof (udp->a));
+ foreach_udp_proto_field;
+#undef _
+
+ *maskp = mask;
+ return 1;
+}
+
+typedef struct {
+ u16 src_port, dst_port;
+} tcpudp_header_t;
+
+uword unformat_l4_mask (unformat_input_t * input, va_list * args)
+{
+ u8 ** maskp = va_arg (*args, u8 **);
+ u16 src_port = 0, dst_port = 0;
+ tcpudp_header_t * tcpudp;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "tcp %U", unformat_tcp_mask, maskp))
+ return 1;
+ else if (unformat (input, "udp %U", unformat_udp_mask, maskp))
+ return 1;
+ else if (unformat (input, "src_port"))
+ src_port = 0xFFFF;
+ else if (unformat (input, "dst_port"))
+ dst_port = 0xFFFF;
+ else
+ return 0;
+ }
+
+ if (!src_port && !dst_port)
+ return 0;
+
+ u8 * mask = 0;
+ vec_validate (mask, sizeof (tcpudp_header_t) - 1);
+
+ tcpudp = (tcpudp_header_t *) mask;
+ tcpudp->src_port = src_port;
+ tcpudp->dst_port = dst_port;
+
+ *maskp = mask;
+
+ return 1;
+}
+
uword unformat_ip4_mask (unformat_input_t * input, va_list * args)
{
u8 ** maskp = va_arg (*args, u8 **);
u8 * mask = 0;
u8 * l2 = 0;
u8 * l3 = 0;
+ u8 * l4 = 0;
int i;
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
;
else if (unformat (input, "l3 %U", unformat_l3_mask, &l3))
;
+ else if (unformat (input, "l4 %U", unformat_l4_mask, &l4))
+ ;
else
break;
}
- if (mask || l2 || l3)
+ if (l4 && !l3) {
+ vec_free (mask);
+ vec_free (l2);
+ vec_free (l4);
+ return 0;
+ }
+
+ if (mask || l2 || l3 || l4)
{
- if (l2 || l3)
+ if (l2 || l3 || l4)
{
/* "With a free Ethernet header in every package" */
if (l2 == 0)
vec_append (mask, l3);
vec_free (l3);
}
+ if (l4)
+ {
+ vec_append (mask, l4);
+ vec_free (l4);
+ }
}
/* Scan forward looking for the first significant mask octet */
}
#define foreach_ip_next \
-_(miss, MISS) \
_(drop, DROP) \
-_(local, LOCAL) \
_(rewrite, REWRITE)
uword unformat_ip_next_index (unformat_input_t * input, va_list * args)
u32 miss_next_index = ~0;
u32 memory_size = 2<<20;
u32 tmp;
+ u32 current_data_flag = 0;
+ int current_data_offset = 0;
u8 * mask = 0;
vnet_classify_main_t * cm = &vnet_classify_main;
else if (unformat (input, "acl-miss-next %U", unformat_acl_next_index,
&miss_next_index))
;
-
+ else if (unformat (input, "current-data-flag %d", ¤t_data_flag))
+ ;
+ else if (unformat (input, "current-data-offset %d", ¤t_data_offset))
+ ;
+
else
break;
}
- if (is_add && mask == 0)
+ if (is_add && mask == 0 && table_index == ~0)
return clib_error_return (0, "Mask required");
- if (is_add && skip == ~0)
+ if (is_add && skip == ~0 && table_index == ~0)
return clib_error_return (0, "skip count required");
- if (is_add && match == ~0)
+ if (is_add && match == ~0 && table_index == ~0)
return clib_error_return (0, "match count required");
if (!is_add && table_index == ~0)
rv = vnet_classify_add_del_table (cm, mask, nbuckets, memory_size,
skip, match, next_table_index, miss_next_index,
- &table_index, is_add);
+ &table_index, current_data_flag, current_data_offset, is_add);
switch (rv)
{
case 0:
.path = "classify table",
.short_help =
"classify table [miss-next|l2-miss_next|acl-miss-next <next_index>]"
- "\n mask <mask-value> buckets <nn> [skip <n>] [match <n>] [del]",
+ "\n mask <mask-value> buckets <nn> [skip <n>] [match <n>]"
+ "\n [current-data-flag <n>] [current-data-offset <n>] [table <n>] [del]",
.function = classify_table_command_fn,
};
s = format (s, "\n Heap: %U", format_mheap, t->mheap, 0 /*verbose*/);
- s = format (s, "\n nbuckets %d, skip %d match %d",
- t->nbuckets, t->skip_n_vectors, t->match_n_vectors);
+ s = format (s, "\n nbuckets %d, skip %d match %d flag %d offset %d",
+ t->nbuckets, t->skip_n_vectors, t->match_n_vectors,
+ t->current_data_flag, t->current_data_offset);
s = format (s, "\n mask %U", format_hex_bytes, t->mask,
t->match_n_vectors * sizeof (u32x4));
.function = show_classify_tables_command_fn,
};
+uword unformat_l4_match (unformat_input_t * input, va_list * args)
+{
+ u8 ** matchp = va_arg (*args, u8 **);
+
+ u8 * proto_header = 0;
+ int src_port = 0;
+ int dst_port = 0;
+
+ tcpudp_header_t h;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "src_port %d", &src_port))
+ ;
+ else if (unformat (input, "dst_port %d", &dst_port))
+ ;
+ else
+ return 0;
+ }
+
+ h.src_port = clib_host_to_net_u16(src_port);
+ h.dst_port = clib_host_to_net_u16(dst_port);
+ vec_validate(proto_header, sizeof(h)-1);
+ memcpy(proto_header, &h, sizeof(h));
+
+ *matchp = proto_header;
+
+ return 1;
+}
+
uword unformat_ip4_match (unformat_input_t * input, va_list * args)
{
u8 ** matchp = va_arg (*args, u8 **);
ip->tos = tos_val;
if (length)
- ip->length = length_val;
+ ip->length = clib_host_to_net_u16 (length_val);
if (ttl)
ip->ttl = ttl_val;
if (checksum)
- ip->checksum = checksum_val;
+ ip->checksum = clib_host_to_net_u16 (checksum_val);
*matchp = match;
return 1;
u8 * match = 0;
u8 * l2 = 0;
u8 * l3 = 0;
+ u8 * l4 = 0;
if (pool_is_free_index (cm->tables, table_index))
return 0;
;
else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
;
+ else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
+ ;
else
break;
}
- if (match || l2 || l3)
+ if (l4 && !l3) {
+ vec_free (match);
+ vec_free (l2);
+ vec_free (l4);
+ return 0;
+ }
+
+ if (match || l2 || l3 || l4)
{
- if (l2 || l3)
+ if (l2 || l3 || l4)
{
/* "Win a free Ethernet header in every packet" */
if (l2 == 0)
vec_append_aligned (match, l3, sizeof(u32x4));
vec_free (l3);
}
+ if (l4)
+ {
+ vec_append_aligned (match, l4, sizeof(u32x4));
+ vec_free (l4);
+ }
}
/* Make sure the vector is big enough even if key is all 0's */
u32 hit_next_index,
u32 opaque_index,
i32 advance,
+ u8 action,
+ u32 metadata,
int is_add)
{
vnet_classify_table_t * t;
e->hits = 0;
e->last_heard = 0;
e->flags = 0;
+ e->action = action;
+ if (e->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX)
+ e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, metadata);
+ else if (e->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
+ e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, metadata);
/* Copy key data, honoring skip_n_vectors */
clib_memcpy (&e->key, match + t->skip_n_vectors * sizeof (u32x4),
u64 opaque_index = ~0;
u8 * match = 0;
i32 advance = 0;
+ u32 action = 0;
+ u32 metadata = 0;
int i, rv;
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
;
else if (unformat (input, "table-index %d", &table_index))
;
+ else if (unformat (input, "action set-ip4-fib-id %d", &metadata))
+ action = 1;
+ else if (unformat (input, "action set-ip6-fib-id %d", &metadata))
+ action = 2;
else
{
/* Try registered opaque-index unformat fns */
rv = vnet_classify_add_del_session (cm, table_index, match,
hit_next_index,
- opaque_index, advance, is_add);
+ opaque_index, advance,
+ action, metadata, is_add);
switch(rv)
{
VLIB_CLI_COMMAND (classify_session_command, static) = {
.path = "classify session",
- .short_help =
- "classify session [hit-next|l2-hit-next|acl-hit-next <next_index>|"
- "policer-hit-next <policer_name>]"
- "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]",
+ .short_help =
+ "classify session [hit-next|l2-hit-next|"
+ "acl-hit-next <next_index>|policer-hit-next <policer_name>]"
+ "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]"
+ "\n [action set-ip4-fib-id <n>] [action set-ip6-fib-id <n>] [del]",
.function = classify_session_command_fn,
};
return 0;
}
-static uword
+static uword
unformat_ip_next_node (unformat_input_t * input, va_list * args)
{
vnet_classify_main_t * cm = &vnet_classify_main;
u32 * next_indexp = va_arg (*args, u32 *);
u32 node_index;
- u32 next_index, rv;
+ u32 next_index = ~0;
- if (unformat (input, "node %U", unformat_vlib_node,
+ if (unformat (input, "ip6-node %U", unformat_vlib_node,
cm->vlib_main, &node_index))
{
- rv = next_index = vlib_node_add_next
- (cm->vlib_main, ip4_classify_node.index, node_index);
- next_index = vlib_node_add_next
- (cm->vlib_main, ip6_classify_node.index, node_index);
- ASSERT(rv == next_index);
-
- *next_indexp = next_index;
- return 1;
+ next_index = vlib_node_add_next (cm->vlib_main,
+ ip6_classify_node.index, node_index);
}
- return 0;
+ else if (unformat (input, "ip4-node %U", unformat_vlib_node,
+ cm->vlib_main, &node_index))
+ {
+ next_index = vlib_node_add_next (cm->vlib_main,
+ ip4_classify_node.index, node_index);
+ }
+ else
+ return 0;
+
+ *next_indexp = next_index;
+ return 1;
}
static uword
vnet_classify_main_t * cm = &vnet_classify_main;
u32 * next_indexp = va_arg (*args, u32 *);
u32 node_index;
- u32 next_index, rv;
+ u32 next_index;
- if (unformat (input, "node %U", unformat_vlib_node,
+ if (unformat (input, "ip6-node %U", unformat_vlib_node,
cm->vlib_main, &node_index))
{
- rv = next_index = vlib_node_add_next
- (cm->vlib_main, ip4_inacl_node.index, node_index);
- next_index = vlib_node_add_next
- (cm->vlib_main, ip6_inacl_node.index, node_index);
- ASSERT(rv == next_index);
-
- *next_indexp = next_index;
- return 1;
+ next_index = vlib_node_add_next (cm->vlib_main,
+ ip6_inacl_node.index, node_index);
}
- return 0;
+ else if (unformat (input, "ip4-node %U", unformat_vlib_node,
+ cm->vlib_main, &node_index))
+ {
+ next_index = vlib_node_add_next (cm->vlib_main,
+ ip4_inacl_node.index, node_index);
+ }
+ else
+ return 0;
+
+ *next_indexp = next_index;
+ return 1;
}
static uword
vnet_classify_register_unformat_l2_next_index_fn
(unformat_l2_input_next_node);
- vnet_classify_register_unformat_l2_next_index_fn
- (unformat_l2_input_next_node);
-
vnet_classify_register_unformat_l2_next_index_fn
(unformat_l2_output_next_node);
memory_size,
0 /* skip */,
3 /* vectors to match */);
- t->miss_next_index = IP_LOOKUP_NEXT_LOCAL;
+ t->miss_next_index = IP_LOOKUP_NEXT_DROP;
vlib_cli_output (vm, "Create table %d", t - cm->tables);
}
rv = vnet_classify_add_del_session (cm, t - cm->tables, (u8 *) data,
IP_LOOKUP_NEXT_DROP,
i+100 /* opaque_index */,
- 0 /* advance */,
+ 0 /* advance */, 0, 0,
1 /* is_add */);
if (rv != 0)
rv = vnet_classify_add_del_session (cm, t - cm->tables, key_minus_skip,
IP_LOOKUP_NEXT_DROP,
i+100 /* opaque_index */,
- 0 /* advance */,
+ 0 /* advance */, 0, 0,
0 /* is_add */);
if (rv != 0)
clib_warning ("del: returned %d", rv);