diff options
author | Pierre Pfister <ppfister@cisco.com> | 2016-06-30 15:33:26 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@fd.io> | 2016-06-30 15:33:26 +0000 |
commit | 593607aae6018d962ecd56fe4c46c3b0ad97e78c (patch) | |
tree | 87ce60aecf8c3f13e0974f86d35b1fd76391f723 /router | |
parent | f7b47573a300f29fdc599e6adc8be20c2dee6313 (diff) | |
parent | 3c93dba70e2aaabcd1a68d6c896a8177487e3477 (diff) |
Merge changes from topic 'cleanup'
* changes:
[router] Remove note about build failure.
[router] Support tcp injection on tapped interfaces.
[router] Combine node functions.
Diffstat (limited to 'router')
-rw-r--r-- | router/README.md | 5 | ||||
-rw-r--r-- | router/router/router.c | 471 |
2 files changed, 201 insertions, 275 deletions
diff --git a/router/README.md b/router/README.md index 5796b83..b4e8ce0 100644 --- a/router/README.md +++ b/router/README.md @@ -36,12 +36,9 @@ $ cd build-root $ ./bootstrap.sh $ make V=0 PLATFORM=vpp TAG=vpp_debug router-install $ ln -sf /git/vpp/build-root/install-vpp_debug-native/router/lib64/router.so.0.0.0 \ - /usr/lib/vpp_plugins/ + /usr/lib/vpp_plugins/router.so ``` -NOTE: The 'make' command above may fail twice when building netlink. If an -error occurs, retry the make command two more times. - Once VPP is running and the plugin is loaded, data plane interfaces can be tapped. diff --git a/router/router/router.c b/router/router/router.c index 571db20..4d72c1b 100644 --- a/router/router/router.c +++ b/router/router/router.c @@ -26,34 +26,22 @@ #include <vnet/ethernet/arp_packet.h> enum { - NEXT_ARP = 0, - NEXT_ICMP = 0, - NEXT_INJECT_ARP_ICMP, + NEXT_UNTAPPED = 0, + NEXT_INJECT, }; enum { - NEXT_DROP, - NEXT_INJECT_CLASSIFIED, -}; - -enum { - ERROR_DROP = 0, ERROR_INJECT_ARP, ERROR_INJECT_ICMP, ERROR_INJECT_CLASSIFIED, }; static char *error_strings[] = { - [ERROR_DROP] = "Untapped interface", [ERROR_INJECT_ARP] = "Inject ARP", [ERROR_INJECT_ICMP] = "Inject ICMP", [ERROR_INJECT_CLASSIFIED] = "Inject Classified", }; -vlib_node_registration_t tap_inject_arp_node; -vlib_node_registration_t tap_inject_icmp_node; -vlib_node_registration_t tap_inject_classified_node; - struct tap_to_iface { u32 tap; u32 iface; @@ -68,6 +56,191 @@ struct router_main { static struct router_main rm; +vlib_node_registration_t tap_inject_arp_node; +vlib_node_registration_t tap_inject_icmp_node; +vlib_node_registration_t tap_inject_classified_node; + +static inline void +update_arp_entry(vlib_buffer_t *b0, ethernet_arp_header_t *arp, u32 vlib_rx) +{ + ethernet_header_t *eth; + ip4_address_t *if_addr; + ip_interface_address_t *ifa; + + if (arp->l2_type != ntohs(ETHERNET_ARP_HARDWARE_TYPE_ethernet) || + arp->l3_type != ntohs(ETHERNET_TYPE_IP4)) + return; + + /* Check that IP address is local and matches incoming interface. */ + if_addr = ip4_interface_address_matching_destination(&ip4_main, + &arp->ip4_over_ethernet[1].ip4, + vlib_rx, &ifa); + if (!if_addr) + return; + + /* Source must also be local to subnet of matching interface address. */ + if (!ip4_destination_matches_interface(&ip4_main, + &arp->ip4_over_ethernet[0].ip4, ifa)) + return; + + /* Reject replies with our local interface address. */ + if (if_addr->as_u32 == arp->ip4_over_ethernet[0].ip4.as_u32) + return; + + if (if_addr->as_u32 != arp->ip4_over_ethernet[1].ip4.as_u32) + return; + + eth = ethernet_buffer_get_header(b0); + + /* Trash ARP packets whose ARP-level source addresses do not + * match their L2-frame-level source addresses */ + if (memcmp(eth->src_address, arp->ip4_over_ethernet[0].ethernet, + sizeof(eth->src_address))) + return; + + if (arp->ip4_over_ethernet[0].ip4.as_u32 == 0 || + (arp->ip4_over_ethernet[0].ip4.as_u32 == + arp->ip4_over_ethernet[1].ip4.as_u32)) + return; + + /* Learn or update sender's mapping only for requests or unicasts + * that don't match local interface address. */ + if (ethernet_address_cast(eth->dst_address) != ETHERNET_ADDRESS_UNICAST) + return; + + vnet_arp_set_ip4_over_ethernet(rm.vnet_main, vlib_rx, ~0, + &arp->ip4_over_ethernet[0], 0); +} + +static uword +tap_inject_func(vlib_main_t *m, vlib_node_runtime_t *node, vlib_frame_t *f, + int mode) +{ + u32 n_left_from = f->n_vectors; + u32 *from = vlib_frame_vector_args(f); + u32 next_index = node->cached_next_index; + u32 *to_next; + u32 counter, count = 0; + + while (n_left_from) { + vlib_buffer_t *b0; + u32 next0, bi0, n_left; + u32 vlib_rx, vlib_tx; + + vlib_get_next_frame(m, node, next_index, to_next, n_left); + + *(to_next++) = bi0 = *(from++); + --n_left_from; + --n_left; + + b0 = vlib_get_buffer(m, bi0); + + vlib_rx = vnet_buffer(b0)->sw_if_index[VLIB_RX]; + vlib_tx = rm.iface_to_tap[vlib_rx]; + + if (vlib_tx == 0 || vlib_tx == ~0) { + next0 = NEXT_UNTAPPED; + goto untapped; + } + + next0 = NEXT_INJECT; + vnet_buffer(b0)->sw_if_index[VLIB_TX] = vlib_tx; + ++count; + + if (mode == ERROR_INJECT_ARP) { + ethernet_arp_header_t *arphdr; + + arphdr = vlib_buffer_get_current(b0); + if (arphdr->opcode == ntohs(ETHERNET_ARP_OPCODE_reply)) + update_arp_entry(b0, arphdr, vlib_rx); + } + + /* FIXME: What about VLAN? */ + b0->current_data -= sizeof(ethernet_header_t); + b0->current_length += sizeof(ethernet_header_t); + +untapped: + vlib_validate_buffer_enqueue_x1(m, node, next_index, to_next, + n_left, bi0, next0); + vlib_put_next_frame(m, node, next_index, n_left); + } + + switch (mode) { + case ERROR_INJECT_ARP: + counter = ERROR_INJECT_ARP; + break; + case ERROR_INJECT_ICMP: + counter = ERROR_INJECT_ICMP; + break; + default: + counter = ERROR_INJECT_CLASSIFIED; + } + + vlib_node_increment_counter(m, node->node_index, counter, count); + return f->n_vectors; +} + +static uword +tap_inject_arp(vlib_main_t *m, vlib_node_runtime_t *node, vlib_frame_t *f) +{ + return tap_inject_func(m, node, f, ERROR_INJECT_ARP); +} + +VLIB_REGISTER_NODE(tap_inject_arp_node) = { + .function = tap_inject_arp, + .name = "tap-inject-arp", + .vector_size = sizeof(u32), + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN(error_strings), + .error_strings = error_strings, + .n_next_nodes = 2, + .next_nodes = { + [NEXT_UNTAPPED] = "arp-input", + [NEXT_INJECT] = "interface-output", + }, +}; + +static uword +tap_inject_icmp(vlib_main_t *m, vlib_node_runtime_t *node, vlib_frame_t *f) +{ + return tap_inject_func(m, node, f, ERROR_INJECT_ICMP); +} + +VLIB_REGISTER_NODE(tap_inject_icmp_node) = { + .function = tap_inject_icmp, + .name = "tap-inject-icmp", + .vector_size = sizeof(u32), + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN(error_strings), + .error_strings = error_strings, + .n_next_nodes = 2, + .next_nodes = { + [NEXT_UNTAPPED] = "ip4-icmp-input", + [NEXT_INJECT] = "interface-output", + }, +}; + +static uword +tap_inject_classified(vlib_main_t *m, vlib_node_runtime_t *node, + vlib_frame_t *f) +{ + return tap_inject_func(m, node, f, ERROR_INJECT_CLASSIFIED); +} + +VLIB_REGISTER_NODE(tap_inject_classified_node) = { + .function = tap_inject_classified, + .name = "tap-inject-classified", + .vector_size = sizeof(u32), + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN(error_strings), + .error_strings = error_strings, + .n_next_nodes = 2, + .next_nodes = { + [NEXT_UNTAPPED] = "error-drop", + [NEXT_INJECT] = "interface-output", + }, +}; + static int set_tap_hwaddr(vlib_main_t *m, char *name, u8 *hwaddr) { @@ -113,6 +286,7 @@ enum { PROTO_ARP = 0, PROTO_ICMP4, PROTO_OSPF2, + PROTO_TCP, PROTO_N_TOTAL, }; @@ -120,12 +294,14 @@ enum { PROTO_BIT_ARP = 1 << PROTO_ARP, PROTO_BIT_ICMP4 = 1 << PROTO_ICMP4, PROTO_BIT_OSPF2 = 1 << PROTO_OSPF2, + PROTO_BIT_TCP = 1 << PROTO_TCP, }; static char *proto_strings[PROTO_N_TOTAL] = { [PROTO_ARP] = "arp", [PROTO_ICMP4] = "icmp4", [PROTO_OSPF2] = "ospf2", + [PROTO_TCP] = "tcp", }; static inline u32 parse_protos(char *proto_string) @@ -244,6 +420,11 @@ tap_inject(vlib_main_t *m, unformat_input_t *input, vlib_cli_command_t *cmd) return clib_error_return(0, "ospf2 requires arp and icmp4"); + if (protos & PROTO_BIT_TCP) /* Require arp and icmp4 for tcp. */ + if (!(protos & PROTO_BIT_ARP) || !(protos & PROTO_BIT_ICMP4)) + return clib_error_return(0, + "tcp requires arp and icmp4"); + err = do_tap_connect(m, name, iface, &tap); if (err) { if (tap != ~0) @@ -278,7 +459,11 @@ tap_inject(vlib_main_t *m, unformat_input_t *input, vlib_cli_command_t *cmd) if (protos & PROTO_BIT_OSPF2) ip4_register_protocol(IP_PROTOCOL_OSPF, - tap_inject_icmp_node.index); + tap_inject_classified_node.index); + + if (protos & PROTO_BIT_TCP) + ip4_register_protocol(IP_PROTOCOL_TCP, + tap_inject_classified_node.index); /* Find sw_if_index of tap associated with data plane interface. */ rm.iface_to_tap[iface] = tap; @@ -295,142 +480,6 @@ VLIB_CLI_COMMAND(tap_inject_command, static) = { .function = tap_inject, }; -static uword -tap_inject_arp_icmp(vlib_main_t *m, vlib_node_runtime_t *node, - vlib_frame_t *f, int arp) -{ - u32 n_left_from = f->n_vectors; - u32 *from = vlib_frame_vector_args(f); - u32 next_index = node->cached_next_index; - u32 *to_next; - u32 me = arp ? tap_inject_arp_node.index : tap_inject_icmp_node.index; - - while (n_left_from) { - vlib_buffer_t *b0; - u32 next0; - u32 bi0; - u32 n_left_to_next; - u32 vlib_rx, vlib_tx; - u32 counter; - - vlib_get_next_frame(m, node, next_index, to_next, - n_left_to_next); - - *(to_next++) = bi0 = *(from++); - --n_left_from; - --n_left_to_next; - - b0 = vlib_get_buffer(m, bi0); - - /* FIXME: What about VLAN? */ - b0->current_data -= sizeof(ethernet_header_t); - b0->current_length += sizeof(ethernet_header_t); - - vlib_rx = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - vlib_tx = rm.iface_to_tap[vlib_rx]; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = vlib_tx; - - if (vlib_tx == 0 || vlib_tx == ~0) - next0 = arp ? NEXT_ARP : NEXT_ICMP; - else { - next0 = NEXT_INJECT_ARP_ICMP; - counter = arp ? ERROR_INJECT_ARP : ERROR_INJECT_ICMP; - vlib_node_increment_counter(m, me, counter, 1); - } - - vlib_validate_buffer_enqueue_x1(m, node, next_index, to_next, - n_left_to_next, bi0, next0); - vlib_put_next_frame(m, node, next_index, n_left_to_next); - } - return f->n_vectors; -} - -static uword -tap_inject_icmp(vlib_main_t *m, vlib_node_runtime_t *node, vlib_frame_t *f) -{ - return tap_inject_arp_icmp(m, node, f, 0 /* ICMP */); -} - -VLIB_REGISTER_NODE(tap_inject_icmp_node) = { - .function = tap_inject_icmp, - .name = "tap-inject-icmp", - .vector_size = sizeof(u32), - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN(error_strings), - .error_strings = error_strings, - .n_next_nodes = 2, - .next_nodes = { - [NEXT_ICMP] = "ip4-icmp-input", - [NEXT_INJECT_ARP_ICMP] = "interface-output", - }, -}; - -static uword -tap_inject_classified(vlib_main_t *m, vlib_node_runtime_t *node, - vlib_frame_t *f) -{ - u32 n_left_from = f->n_vectors; - u32 *from = vlib_frame_vector_args(f); - u32 next_index = node->cached_next_index; - u32 *to_next; - u32 out = 0, drop = 0; - - while (n_left_from) { - vlib_buffer_t *b0; - u32 next0; - u32 bi0; - u32 n_left_to_next; - u32 vlib_rx, vlib_tx; - - vlib_get_next_frame(m, node, next_index, to_next, - n_left_to_next); - - *(to_next++) = bi0 = *(from++); - --n_left_from; - --n_left_to_next; - - b0 = vlib_get_buffer(m, bi0); - - /* FIXME: What about VLAN? */ - b0->current_data -= sizeof(ethernet_header_t); - b0->current_length += sizeof(ethernet_header_t); - - vlib_rx = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - vlib_tx = rm.iface_to_tap[vlib_rx]; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = vlib_tx; - - if (vlib_tx == 0 || vlib_tx == ~0) { - next0 = NEXT_DROP; - ++drop; - } else { - next0 = NEXT_INJECT_CLASSIFIED; - ++out; - } - vlib_validate_buffer_enqueue_x1(m, node, next_index, to_next, - n_left_to_next, bi0, next0); - vlib_put_next_frame(m, node, next_index, n_left_to_next); - } - vlib_node_increment_counter(m, tap_inject_classified_node.index, - ERROR_DROP, drop); - vlib_node_increment_counter(m, tap_inject_classified_node.index, - ERROR_INJECT_CLASSIFIED, out); - return f->n_vectors; -} - -VLIB_REGISTER_NODE(tap_inject_classified_node) = { - .function = tap_inject_classified, - .name = "tap-inject-classified", - .vector_size = sizeof(u32), - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN(error_strings), - .error_strings = error_strings, - .n_next_nodes = 2, - .next_nodes = { - [NEXT_DROP] = "error-drop", - [NEXT_INJECT_CLASSIFIED] = "interface-output", - }, -}; - static clib_error_t * interface_add_del(struct vnet_main_t *m, u32 hw_if_index, u32 add) { @@ -457,123 +506,3 @@ static clib_error_t *router_init(vlib_main_t *m) return 0; } VLIB_INIT_FUNCTION(router_init); - -static inline void -update_arp_entry(vlib_buffer_t *b0, ethernet_arp_header_t *arp, u32 vlib_rx) -{ - ethernet_header_t *eth; - ip4_address_t *if_addr; - ip_interface_address_t *ifa; - - if (arp->l2_type != ntohs(ETHERNET_ARP_HARDWARE_TYPE_ethernet) || - arp->l3_type != ntohs(ETHERNET_TYPE_IP4)) - return; - - /* Check that IP address is local and matches incoming interface. */ - if_addr = ip4_interface_address_matching_destination(&ip4_main, - &arp->ip4_over_ethernet[1].ip4, - vlib_rx, &ifa); - if (!if_addr) - return; - - /* Source must also be local to subnet of matching interface address. */ - if (!ip4_destination_matches_interface(&ip4_main, - &arp->ip4_over_ethernet[0].ip4, ifa)) - return; - - /* Reject replies with our local interface address. */ - if (if_addr->as_u32 == arp->ip4_over_ethernet[0].ip4.as_u32) - return; - - if (if_addr->as_u32 != arp->ip4_over_ethernet[1].ip4.as_u32) - return; - - eth = ethernet_buffer_get_header(b0); - - /* Trash ARP packets whose ARP-level source addresses do not - * match their L2-frame-level source addresses */ - if (memcmp(eth->src_address, arp->ip4_over_ethernet[0].ethernet, - sizeof(eth->src_address))) - return; - - if (arp->ip4_over_ethernet[0].ip4.as_u32 == 0 || - (arp->ip4_over_ethernet[0].ip4.as_u32 == - arp->ip4_over_ethernet[1].ip4.as_u32)) - return; - - /* Learn or update sender's mapping only for requests or unicasts - * that don't match local interface address. */ - if (ethernet_address_cast(eth->dst_address) != ETHERNET_ADDRESS_UNICAST) - return; - - vnet_arp_set_ip4_over_ethernet(rm.vnet_main, vlib_rx, ~0, - &arp->ip4_over_ethernet[0], 0); -} - -static uword -tap_inject_arp(vlib_main_t *m, vlib_node_runtime_t *node, vlib_frame_t *f) -{ - u32 n_left_from = f->n_vectors; - u32 *from = vlib_frame_vector_args(f); - u32 next_index = node->cached_next_index; - u32 *to_next; - u32 out = 0; - - while (n_left_from) { - vlib_buffer_t *b0; - u32 next0, bi0, n_left; - u32 vlib_rx, vlib_tx; - ethernet_arp_header_t *arp; - - vlib_get_next_frame(m, node, next_index, to_next, n_left); - - *(to_next++) = bi0 = *(from++); - --n_left_from; - --n_left; - - b0 = vlib_get_buffer(m, bi0); - arp = vlib_buffer_get_current(b0); - - /* FIXME: What about VLAN? */ - b0->current_data -= sizeof(ethernet_header_t); - b0->current_length += sizeof(ethernet_header_t); - - vlib_rx = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - vlib_tx = rm.iface_to_tap[vlib_rx]; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = vlib_tx; - - if (vlib_tx == 0 || vlib_tx == ~0) - next0 = NEXT_ARP; - else { - next0 = NEXT_INJECT_ARP_ICMP; - ++out; - } - - /* Add an ARP entry for injected replies. */ - if (next0 == NEXT_INJECT_ARP_ICMP && - arp->opcode == ntohs(ETHERNET_ARP_OPCODE_reply)) - update_arp_entry(b0, arp, vlib_rx); - - vlib_validate_buffer_enqueue_x1(m, node, next_index, to_next, - n_left, bi0, next0); - vlib_put_next_frame(m, node, next_index, n_left); - } - - vlib_node_increment_counter(m, tap_inject_arp_node.index, - ERROR_INJECT_ARP, out); - return f->n_vectors; -} - -VLIB_REGISTER_NODE(tap_inject_arp_node) = { - .function = tap_inject_arp, - .name = "tap-inject-arp", - .vector_size = sizeof(u32), - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN(error_strings), - .error_strings = error_strings, - .n_next_nodes = 2, - .next_nodes = { - [NEXT_ARP] = "arp-input", - [NEXT_INJECT_ARP_ICMP] = "interface-output", - }, -}; |