From b1fd80f0999e4dbbebdbc2471aeab2cad418ca4d Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Tue, 12 May 2020 13:33:56 +0000 Subject: ipsec: Support 4o6 and 6o4 for SPD tunnel mode SAs Type: feature the es4-encrypt and esp6-encrypt nodes need to be siblings so they both have the same edges for the DPO on which the tunnel mode SA stacks. Signed-off-by: Neale Ranns Change-Id: I2126589135a1df6c95ee14503dfde9ff406df60a --- src/scripts/vnet/ipsec_spd | 55 ++++++++++++++++++++++++++++++++ src/vnet/ipsec/esp_encrypt.c | 76 ++++++++++++++++++++++++-------------------- src/vnet/ipsec/ipsec_cli.c | 27 +++++++++++++--- test/test_ipsec_esp.py | 76 +++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 195 insertions(+), 39 deletions(-) create mode 100644 src/scripts/vnet/ipsec_spd diff --git a/src/scripts/vnet/ipsec_spd b/src/scripts/vnet/ipsec_spd new file mode 100644 index 00000000000..5acced65793 --- /dev/null +++ b/src/scripts/vnet/ipsec_spd @@ -0,0 +1,55 @@ + +create packet-generator interface pg0 +create packet-generator interface pg1 + +set int ip address pg0 192.168.0.1/24 +set int ip address pg1 192.168.1.1/24 + +pipe create + +ip6 table add 1 +ip table add 1 +set int ip6 table pipe0.1 1 +set int ip table pipe0.1 1 + +set int ip address pipe0.0 2001::1/64 +set int ip address pipe0.1 2001::2/64 +set int unnum pipe0.1 use pg1 + +set int state pg0 up +set int state pg1 up +set int state pipe0 up + +ipsec sa add 20 spi 200 crypto-key 6541686776336961656264656f6f6579 crypto-alg aes-cbc-128 tunnel-src 2001::1 tunnel-dst 2001::2 +ipsec sa add 30 spi 200 crypto-key 6541686776336961656264656f6f6579 crypto-alg aes-cbc-128 tunnel-src 2001::1 tunnel-dst 2001::2 + +ipsec spd add 1 +ipsec spd add 2 +set interface ipsec spd pipe0.0 1 +set interface ipsec spd pipe0.1 2 +ipsec policy add spd 1 ip6 priority 100 outbound action bypass protocol 50 +ipsec policy add spd 1 priority 10 outbound action protect sa 20 local-ip-range 192.168.0.0 - 192.168.0.255 remote-ip-range 10.6.0.0 - 10.6.255.255 + +ipsec policy add spd 2 priority 10 inbound action protect sa 30 local-ip-range 2001::2 - 2001::2 remote-ip-range 2001::1 - 2001::1 + +ip route add 10.6.0.0/16 via pipe0.0 +ip route table 1 add 10.6.0.0/16 via 192.168.1.2 pg1 +set ip neighbor pg1 192.168.1.2 00:11:22:33:44:55 + + +trace add pg-input 100 + +packet-generator new { + name ipsec1 + limit 1 + rate 1e4 + node ip4-input + interface pg0 + size 100-100 + data { + UDP: 192.168.0.2 -> 10.6.0.1 + UDP: 4321 -> 1234 + length 72 + incrementing 100 + } +} diff --git a/src/vnet/ipsec/esp_encrypt.c b/src/vnet/ipsec/esp_encrypt.c index 15f590acbdb..e9feb8b40a1 100644 --- a/src/vnet/ipsec/esp_encrypt.c +++ b/src/vnet/ipsec/esp_encrypt.c @@ -27,9 +27,11 @@ #include #define foreach_esp_encrypt_next \ -_(DROP, "error-drop") \ +_(DROP4, "ip4-drop") \ +_(DROP6, "ip6-drop") \ _(PENDING, "pending") \ -_(HANDOFF, "handoff") \ +_(HANDOFF4, "handoff4") \ +_(HANDOFF6, "handoff6") \ _(INTERFACE_OUTPUT, "interface-output") #define _(v, s) ESP_ENCRYPT_NEXT_##v, @@ -235,7 +237,8 @@ esp_get_ip6_hdr_len (ip6_header_t * ip6, ip6_ext_header_t ** ext_hdr) static_always_inline void esp_process_chained_ops (vlib_main_t * vm, vlib_node_runtime_t * node, vnet_crypto_op_t * ops, vlib_buffer_t * b[], - u16 * nexts, vnet_crypto_op_chunk_t * chunks) + u16 * nexts, vnet_crypto_op_chunk_t * chunks, + u16 drop_next) { u32 n_fail, n_ops = vec_len (ops); vnet_crypto_op_t *op = ops; @@ -253,7 +256,7 @@ esp_process_chained_ops (vlib_main_t * vm, vlib_node_runtime_t * node, { u32 bi = op->user_data; b[bi]->error = node->errors[ESP_ENCRYPT_ERROR_CRYPTO_ENGINE_ERROR]; - nexts[bi] = ESP_ENCRYPT_NEXT_DROP; + nexts[bi] = drop_next; n_fail--; } op++; @@ -262,7 +265,8 @@ esp_process_chained_ops (vlib_main_t * vm, vlib_node_runtime_t * node, static_always_inline void esp_process_ops (vlib_main_t * vm, vlib_node_runtime_t * node, - vnet_crypto_op_t * ops, vlib_buffer_t * b[], u16 * nexts) + vnet_crypto_op_t * ops, vlib_buffer_t * b[], u16 * nexts, + u16 drop_next) { u32 n_fail, n_ops = vec_len (ops); vnet_crypto_op_t *op = ops; @@ -280,7 +284,7 @@ esp_process_ops (vlib_main_t * vm, vlib_node_runtime_t * node, { u32 bi = op->user_data; b[bi]->error = node->errors[ESP_ENCRYPT_ERROR_CRYPTO_ENGINE_ERROR]; - nexts[bi] = ESP_ENCRYPT_NEXT_DROP; + nexts[bi] = drop_next; n_fail--; } op++; @@ -555,13 +559,14 @@ out: /* when submitting a frame is failed, drop all buffers in the frame */ static_always_inline void esp_async_recycle_failed_submit (vnet_crypto_async_frame_t * f, - vlib_buffer_t ** b, u16 * next) + vlib_buffer_t ** b, u16 * next, + u16 drop_next) { u32 n_drop = f->n_elts; while (--n_drop) { (b - n_drop)[0]->error = ESP_ENCRYPT_ERROR_CRYPTO_ENGINE_ERROR; - (next - n_drop)[0] = ESP_ENCRYPT_NEXT_DROP; + (next - n_drop)[0] = drop_next; } vnet_crypto_async_reset_frame (f); } @@ -590,6 +595,7 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vnet_crypto_async_frame_t *async_frame = 0; int is_async = im->async_mode; vnet_crypto_async_op_id_t last_async_op = ~0; + u16 drop_next = (is_ip6 ? ESP_ENCRYPT_NEXT_DROP6 : ESP_ENCRYPT_NEXT_DROP4); vlib_get_buffers (vm, from, b, n_left); if (!is_async) @@ -653,7 +659,8 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node, { if (vnet_crypto_async_submit_open_frame (vm, async_frame) < 0) - esp_async_recycle_failed_submit (async_frame, b, next); + esp_async_recycle_failed_submit (async_frame, b, + next, drop_next); } async_frame = vnet_crypto_async_get_frame (vm, sa0->crypto_async_enc_op_id); @@ -672,7 +679,8 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node, if (PREDICT_TRUE (thread_index != sa0->encrypt_thread_index)) { - next[0] = ESP_ENCRYPT_NEXT_HANDOFF; + next[0] = (is_ip6 ? + ESP_ENCRYPT_NEXT_HANDOFF6 : ESP_ENCRYPT_NEXT_HANDOFF4); goto trace; } @@ -681,7 +689,7 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node, if (n_bufs == 0) { b[0]->error = node->errors[ESP_ENCRYPT_ERROR_NO_BUFFERS]; - next[0] = ESP_ENCRYPT_NEXT_DROP; + next[0] = drop_next; goto trace; } @@ -703,7 +711,7 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node, if (PREDICT_FALSE (esp_seq_advance (sa0))) { b[0]->error = node->errors[ESP_ENCRYPT_ERROR_SEQ_CYCLED]; - next[0] = ESP_ENCRYPT_NEXT_DROP; + next[0] = drop_next; goto trace; } @@ -721,7 +729,7 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node, if (!next_hdr_ptr) { b[0]->error = node->errors[ESP_ENCRYPT_ERROR_NO_BUFFERS]; - next[0] = ESP_ENCRYPT_NEXT_DROP; + next[0] = drop_next; goto trace; } b[0]->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID; @@ -884,7 +892,8 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node, icv_sz, from[b - bufs], next, hdr_len, async_next, lb)) { - esp_async_recycle_failed_submit (async_frame, b, next); + esp_async_recycle_failed_submit (async_frame, b, next, + drop_next); goto trace; } } @@ -924,18 +933,18 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node, current_sa_bytes); if (!is_async) { - esp_process_ops (vm, node, ptd->crypto_ops, bufs, nexts); + esp_process_ops (vm, node, ptd->crypto_ops, bufs, nexts, drop_next); esp_process_chained_ops (vm, node, ptd->chained_crypto_ops, bufs, nexts, - ptd->chunks); + ptd->chunks, drop_next); - esp_process_ops (vm, node, ptd->integ_ops, bufs, nexts); + esp_process_ops (vm, node, ptd->integ_ops, bufs, nexts, drop_next); esp_process_chained_ops (vm, node, ptd->chained_integ_ops, bufs, nexts, - ptd->chunks); + ptd->chunks, drop_next); } else if (async_frame && async_frame->n_elts) { if (vnet_crypto_async_submit_open_frame (vm, async_frame) < 0) - esp_async_recycle_failed_submit (async_frame, b, next); + esp_async_recycle_failed_submit (async_frame, b, next, drop_next); } vlib_node_increment_counter (vm, node->node_index, @@ -1051,8 +1060,10 @@ VLIB_REGISTER_NODE (esp4_encrypt_node) = { .n_next_nodes = ESP_ENCRYPT_N_NEXT, .next_nodes = { - [ESP_ENCRYPT_NEXT_DROP] = "ip4-drop", - [ESP_ENCRYPT_NEXT_HANDOFF] = "esp4-encrypt-handoff", + [ESP_ENCRYPT_NEXT_DROP4] = "ip4-drop", + [ESP_ENCRYPT_NEXT_DROP6] = "ip6-drop", + [ESP_ENCRYPT_NEXT_HANDOFF4] = "esp4-encrypt-handoff", + [ESP_ENCRYPT_NEXT_HANDOFF6] = "esp6-encrypt-handoff", [ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT] = "interface-output", [ESP_ENCRYPT_NEXT_PENDING] = "esp-encrypt-pending", }, @@ -1093,17 +1104,10 @@ VLIB_REGISTER_NODE (esp6_encrypt_node) = { .vector_size = sizeof (u32), .format_trace = format_esp_encrypt_trace, .type = VLIB_NODE_TYPE_INTERNAL, + .sibling_of = "esp4-encrypt", .n_errors = ARRAY_LEN(esp_encrypt_error_strings), .error_strings = esp_encrypt_error_strings, - - .n_next_nodes = ESP_ENCRYPT_N_NEXT, - .next_nodes = { - [ESP_ENCRYPT_NEXT_DROP] = "ip6-drop", - [ESP_ENCRYPT_NEXT_HANDOFF] = "esp6-encrypt-handoff", - [ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT] = "interface-output", - [ESP_ENCRYPT_NEXT_PENDING] = "esp-encrypt-pending", - }, }; /* *INDENT-ON* */ @@ -1120,7 +1124,7 @@ VLIB_REGISTER_NODE (esp6_encrypt_post_node) = { .vector_size = sizeof (u32), .format_trace = format_esp_post_encrypt_trace, .type = VLIB_NODE_TYPE_INTERNAL, - .sibling_of = "esp6-encrypt", + .sibling_of = "esp4-encrypt", .n_errors = ARRAY_LEN(esp_encrypt_error_strings), .error_strings = esp_encrypt_error_strings, @@ -1147,8 +1151,10 @@ VLIB_REGISTER_NODE (esp4_encrypt_tun_node) = { .n_next_nodes = ESP_ENCRYPT_N_NEXT, .next_nodes = { - [ESP_ENCRYPT_NEXT_DROP] = "ip4-drop", - [ESP_ENCRYPT_NEXT_HANDOFF] = "esp4-encrypt-tun-handoff", + [ESP_ENCRYPT_NEXT_DROP4] = "ip4-drop", + [ESP_ENCRYPT_NEXT_DROP6] = "ip6-drop", + [ESP_ENCRYPT_NEXT_HANDOFF4] = "esp4-encrypt-tun-handoff", + [ESP_ENCRYPT_NEXT_HANDOFF6] = "error-drop", [ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT] = "adj-midchain-tx", [ESP_ENCRYPT_NEXT_PENDING] = "esp-encrypt-pending", }, @@ -1194,8 +1200,10 @@ VLIB_REGISTER_NODE (esp6_encrypt_tun_node) = { .n_next_nodes = ESP_ENCRYPT_N_NEXT, .next_nodes = { - [ESP_ENCRYPT_NEXT_DROP] = "ip6-drop", - [ESP_ENCRYPT_NEXT_HANDOFF] = "esp6-encrypt-tun-handoff", + [ESP_ENCRYPT_NEXT_DROP4] = "ip4-drop", + [ESP_ENCRYPT_NEXT_DROP6] = "ip6-drop", + [ESP_ENCRYPT_NEXT_HANDOFF4] = "error-drop", + [ESP_ENCRYPT_NEXT_HANDOFF6] = "esp6-encrypt-tun-handoff", [ESP_ENCRYPT_NEXT_PENDING] = "esp-encrypt-pending", [ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT] = "adj-midchain-tx", }, diff --git a/src/vnet/ipsec/ipsec_cli.c b/src/vnet/ipsec/ipsec_cli.c index 695e5f01c74..4d452d53d22 100644 --- a/src/vnet/ipsec/ipsec_cli.c +++ b/src/vnet/ipsec/ipsec_cli.c @@ -234,13 +234,13 @@ ipsec_policy_add_del_command_fn (vlib_main_t * vm, unformat_input_t _line_input, *line_input = &_line_input; ipsec_policy_t p; int rv, is_add = 0; - u32 tmp, tmp2, stat_index; + u32 tmp, tmp2, stat_index, local_range_set, remote_range_set; clib_error_t *error = NULL; u32 is_outbound; clib_memset (&p, 0, sizeof (p)); p.lport.stop = p.rport.stop = ~0; - is_outbound = 0; + remote_range_set = local_range_set = is_outbound = 0; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -251,6 +251,8 @@ ipsec_policy_add_del_command_fn (vlib_main_t * vm, is_add = 1; else if (unformat (line_input, "del")) is_add = 0; + else if (unformat (line_input, "ip6")) + p.is_ipv6 = 1; else if (unformat (line_input, "spd %u", &p.id)) ; else if (unformat (line_input, "inbound")) @@ -277,22 +279,24 @@ ipsec_policy_add_del_command_fn (vlib_main_t * vm, else if (unformat (line_input, "local-ip-range %U - %U", unformat_ip4_address, &p.laddr.start.ip4, unformat_ip4_address, &p.laddr.stop.ip4)) - ; + local_range_set = 1; else if (unformat (line_input, "remote-ip-range %U - %U", unformat_ip4_address, &p.raddr.start.ip4, unformat_ip4_address, &p.raddr.stop.ip4)) - ; + remote_range_set = 1; else if (unformat (line_input, "local-ip-range %U - %U", unformat_ip6_address, &p.laddr.start.ip6, unformat_ip6_address, &p.laddr.stop.ip6)) { p.is_ipv6 = 1; + local_range_set = 1; } else if (unformat (line_input, "remote-ip-range %U - %U", unformat_ip6_address, &p.raddr.start.ip6, unformat_ip6_address, &p.raddr.stop.ip6)) { p.is_ipv6 = 1; + remote_range_set = 1; } else if (unformat (line_input, "local-port-range %u - %u", &tmp, &tmp2)) { @@ -313,6 +317,21 @@ ipsec_policy_add_del_command_fn (vlib_main_t * vm, } } + if (!remote_range_set) + { + if (p.is_ipv6) + clib_memset (&p.raddr.stop.ip6, 0xff, 16); + else + clib_memset (&p.raddr.stop.ip4, 0xff, 4); + } + if (!local_range_set) + { + if (p.is_ipv6) + clib_memset (&p.laddr.stop.ip6, 0xff, 16); + else + clib_memset (&p.laddr.stop.ip4, 0xff, 4); + } + rv = ipsec_policy_mk_type (is_outbound, p.is_ipv6, p.policy, &p.type); if (rv) diff --git a/test/test_ipsec_esp.py b/test/test_ipsec_esp.py index 6be49ef21ce..036fbf36e55 100644 --- a/test/test_ipsec_esp.py +++ b/test/test_ipsec_esp.py @@ -291,7 +291,81 @@ class TemplateIpsecEsp(ConfigIpsecESP): class TestIpsecEsp1(TemplateIpsecEsp, IpsecTra46Tests, IpsecTun46Tests, IpsecTra6ExtTests): """ Ipsec ESP - TUN & TRA tests """ - pass + + @classmethod + def setUpClass(cls): + super(TestIpsecEsp1, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + super(TestIpsecEsp1, cls).tearDownClass() + + def setUp(self): + super(TestIpsecEsp1, self).setUp() + + def tearDown(self): + super(TestIpsecEsp1, self).tearDown() + + def test_tun_46(self): + """ ipsec 4o6 tunnel """ + # add an SPD entry to direct 2.2.2.2 to the v6 tunnel SA + p6 = self.ipv6_params + p4 = self.ipv4_params + + p6.remote_tun_if_host4 = "2.2.2.2" + e = VppEnum.vl_api_ipsec_spd_action_t + + VppIpsecSpdEntry(self, + self.tun_spd, + p6.scapy_tun_sa_id, + self.pg1.remote_addr[p4.addr_type], + self.pg1.remote_addr[p4.addr_type], + p6.remote_tun_if_host4, + p6.remote_tun_if_host4, + 0, + priority=10, + policy=e.IPSEC_API_SPD_ACTION_PROTECT, + is_outbound=1).add_vpp_config() + VppIpRoute(self, p6.remote_tun_if_host4, p4.addr_len, + [VppRoutePath(self.tun_if.remote_addr[p4.addr_type], + 0xffffffff)]).add_vpp_config() + + old_name = self.tun6_encrypt_node_name + self.tun6_encrypt_node_name = "esp4-encrypt" + + self.verify_tun_46(p6, count=63) + self.tun6_encrypt_node_name = old_name + + def test_tun_64(self): + """ ipsec 6o4 tunnel """ + # add an SPD entry to direct 4444::4 to the v4 tunnel SA + p6 = self.ipv6_params + p4 = self.ipv4_params + + p4.remote_tun_if_host6 = "4444::4" + e = VppEnum.vl_api_ipsec_spd_action_t + + VppIpsecSpdEntry(self, + self.tun_spd, + p4.scapy_tun_sa_id, + self.pg1.remote_addr[p6.addr_type], + self.pg1.remote_addr[p6.addr_type], + p4.remote_tun_if_host6, + p4.remote_tun_if_host6, + 0, + priority=10, + policy=e.IPSEC_API_SPD_ACTION_PROTECT, + is_outbound=1).add_vpp_config() + d = DpoProto.DPO_PROTO_IP6 + VppIpRoute(self, p4.remote_tun_if_host6, p6.addr_len, + [VppRoutePath(self.tun_if.remote_addr[p6.addr_type], + 0xffffffff, + proto=d)]).add_vpp_config() + + old_name = self.tun4_encrypt_node_name + self.tun4_encrypt_node_name = "esp6-encrypt" + self.verify_tun_64(p4, count=63) + self.tun4_encrypt_node_name = old_name class TestIpsecEsp2(TemplateIpsecEsp, IpsecTcpTests): -- cgit 1.2.3-korg