aboutsummaryrefslogtreecommitdiffstats
path: root/test/test_ipsec_esp.py
blob: d254ee76762bf4eb50ed5a70e83427e0da1cfa3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
import socket
import unittest
from scapy.layers.ipsec import ESP
from scapy.layers.inet import UDP

from framework import VppTestRunner
from template_ipsec import IpsecTra46Tests, IpsecTun46Tests, TemplateIpsec, \
    IpsecTcpTests, IpsecTun4Tests, IpsecTra4Tests, config_tra_params
from vpp_ipsec import VppIpsecSpd, VppIpsecSpdEntry, VppIpsecSA,\
        VppIpsecSpdItfBinding
from vpp_ip_route import VppIpRoute, VppRoutePath
from vpp_ip import DpoProto
from vpp_papi import VppEnum


def config_esp_tun(test, params):
    addr_type = params.addr_type
    scapy_tun_sa_id = params.scapy_tun_sa_id
    scapy_tun_spi = params.scapy_tun_spi
    vpp_tun_sa_id = params.vpp_tun_sa_id
    vpp_tun_spi = params.vpp_tun_spi
    auth_algo_vpp_id = params.auth_algo_vpp_id
    auth_key = params.auth_key
    crypt_algo_vpp_id = params.crypt_algo_vpp_id
    crypt_key = params.crypt_key
    remote_tun_if_host = params.remote_tun_if_host
    addr_any = params.addr_any
    addr_bcast = params.addr_bcast
    e = VppEnum.vl_api_ipsec_spd_action_t

    params.tun_sa_in = VppIpsecSA(test, scapy_tun_sa_id, scapy_tun_spi,
                                  auth_algo_vpp_id, auth_key,
                                  crypt_algo_vpp_id, crypt_key,
                                  test.vpp_esp_protocol,
                                  test.tun_if.local_addr[addr_type],
                                  test.tun_if.remote_addr[addr_type])
    params.tun_sa_in.add_vpp_config()
    params.tun_sa_out = VppIpsecSA(test, vpp_tun_sa_id, vpp_tun_spi,
                                   auth_algo_vpp_id, auth_key,
                                   crypt_algo_vpp_id, crypt_key,
                                   test.vpp_esp_protocol,
                                   test.tun_if.remote_addr[addr_type],
                                   test.tun_if.local_addr[addr_type])
    params.tun_sa_out.add_vpp_config()

    params.spd_policy_in_any = VppIpsecSpdEntry(test, test.tun_spd,
                                                scapy_tun_sa_id,
                                                addr_any, addr_bcast,
                                                addr_any, addr_bcast,
                                                socket.IPPROTO_ESP)
    params.spd_policy_in_any.add_vpp_config()
    params.spd_policy_out_any = VppIpsecSpdEntry(test, test.tun_spd,
                                                 scapy_tun_sa_id,
                                                 addr_any, addr_bcast,
                                                 addr_any, addr_bcast,
                                                 socket.IPPROTO_ESP,
                                                 is_outbound=0)
    params.spd_policy_out_any.add_vpp_config()

    VppIpsecSpdEntry(test, test.tun_spd, vpp_tun_sa_id,
                     remote_tun_if_host, remote_tun_if_host,
                     test.pg1.remote_addr[addr_type],
                     test.pg1.remote_addr[addr_type],
                     0,
                     priority=10,
                     policy=e.IPSEC_API_SPD_ACTION_PROTECT,
                     is_outbound=0).add_vpp_config()
    VppIpsecSpdEntry(test, test.tun_spd, scapy_tun_sa_id,
                     test.pg1.remote_addr[addr_type],
                     test.pg1.remote_addr[addr_type],
                     remote_tun_if_host, remote_tun_if_host,
                     0,
                     policy=e.IPSEC_API_SPD_ACTION_PROTECT,
                     priority=10).add_vpp_config()

    VppIpsecSpdEntry(test, test.tun_spd, vpp_tun_sa_id,
                     remote_tun_if_host, remote_tun_if_host,
                     test.pg0.local_addr[addr_type],
                     test.pg0.local_addr[addr_type],
                     0,
                     priority=20,
                     policy=e.IPSEC_API_SPD_ACTION_PROTECT,
                     is_outbound=0).add_vpp_config()
    VppIpsecSpdEntry(test, test.tun_spd, scapy_tun_sa_id,
                     test.pg0.local_addr[addr_type],
                     test.pg0.local_addr[addr_type],
                     remote_tun_if_host, remote_tun_if_host,
                     0,
                     policy=e.IPSEC_API_SPD_ACTION_PROTECT,
                     priority=20).add_vpp_config()


def config_esp_tra(test, params):
    addr_type = params.addr_type
    scapy_tra_sa_id = params.scapy_tra_sa_id
    scapy_tra_spi = params.scapy_tra_spi
    vpp_tra_sa_id = params.vpp_tra_sa_id
    vpp_tra_spi = params.vpp_tra_spi
    auth_algo_vpp_id = params.auth_algo_vpp_id
    auth_key = params.auth_key
    crypt_algo_vpp_id = params.crypt_algo_vpp_id
    crypt_key = params.crypt_key
    addr_any = params.addr_any
    addr_bcast = params.addr_bcast
    flags = (VppEnum.vl_api_ipsec_sad_flags_t.
             IPSEC_API_SAD_FLAG_USE_ANTI_REPLAY)
    e = VppEnum.vl_api_ipsec_spd_action_t
    flags = params.flags | flags

    params.tra_sa_in = VppIpsecSA(test, scapy_tra_sa_id, scapy_tra_spi,
                                  auth_algo_vpp_id, auth_key,
                                  crypt_algo_vpp_id, crypt_key,
                                  test.vpp_esp_protocol,
                                  flags=flags)
    params.tra_sa_in.add_vpp_config()
    params.tra_sa_out = VppIpsecSA(test, vpp_tra_sa_id, vpp_tra_spi,
                                   auth_algo_vpp_id, auth_key,
                                   crypt_algo_vpp_id, crypt_key,
                                   test.vpp_esp_protocol,
                                   flags=flags)
    params.tra_sa_out.add_vpp_config()

    VppIpsecSpdEntry(test, test.tra_spd, vpp_tra_sa_id,
                     addr_any, addr_bcast,
                     addr_any, addr_bcast,
                     socket.IPPROTO_ESP).add_vpp_config()
    VppIpsecSpdEntry(test, test.tra_spd, vpp_tra_sa_id,
                     addr_any, addr_bcast,
                     addr_any, addr_bcast,
                     socket.IPPROTO_ESP,
                     is_outbound=0).add_vpp_config()

    VppIpsecSpdEntry(test, test.tra_spd, vpp_tra_sa_id,
                     test.tra_if.local_addr[addr_type],
                     test.tra_if.local_addr[addr_type],
                     test.tra_if.remote_addr[addr_type],
                     test.tra_if.remote_addr[addr_type],
                     0, priority=10,
                     policy=e.IPSEC_API_SPD_ACTION_PROTECT,
                     is_outbound=0).add_vpp_config()
    VppIpsecSpdEntry(test, test.tra_spd, scapy_tra_sa_id,
                     test.tra_if.local_addr[addr_type],
                     test.tra_if.local_addr[addr_type],
                     test.tra_if.remote_addr[addr_type],
                     test.tra_if.remote_addr[addr_type],
                     0, policy=e.IPSEC_API_SPD_ACTION_PROTECT,
                     priority=10).add_vpp_config()


class TemplateIpsecEsp(TemplateIpsec):
    """
    Basic test for ipsec esp sanity - tunnel and transport modes.

    Below 4 cases are covered as part of this test
    1) ipsec esp v4 transport basic test  - IPv4 Transport mode
        scenario using HMAC-SHA1-96 integrity algo
    2) ipsec esp v4 transport burst test
        Above test for 257 pkts
    3) ipsec esp 4o4 tunnel basic test    - IPv4 Tunnel mode
        scenario using HMAC-SHA1-96 integrity algo
    4) ipsec esp 4o4 tunnel burst test
        Above test for 257 pkts

    TRANSPORT MODE:

     ---   encrypt   ---
    |pg2| <-------> |VPP|
     ---   decrypt   ---

    TUNNEL MODE:

     ---   encrypt   ---   plain   ---
    |pg0| <-------  |VPP| <------ |pg1|
     ---             ---           ---

     ---   decrypt   ---   plain   ---
    |pg0| ------->  |VPP| ------> |pg1|
     ---             ---           ---
    """

    def setUp(self):
        super(TemplateIpsecEsp, self).setUp()
        self.encryption_type = ESP
        self.tun_if = self.pg0
        self.tra_if = self.pg2
        self.logger.info(self.vapi.ppcli("show int addr"))

        self.tra_spd = VppIpsecSpd(self, self.tra_spd_id)
        self.tra_spd.add_vpp_config()
        VppIpsecSpdItfBinding(self, self.tra_spd,
                              self.tra_if).add_vpp_config()

        for _, p in self.params.items():
            config_esp_tra(self, p)
            config_tra_params(p, self.encryption_type)
        self.logger.info(self.vapi.ppcli("show ipsec"))

        self.tun_spd = VppIpsecSpd(self, self.tun_spd_id)
        self.tun_spd.add_vpp_config()
        VppIpsecSpdItfBinding(self, self.tun_spd,
                              self.tun_if).add_vpp_config()

        for _, p in self.params.items():
            config_esp_tun(self, p)
        self.logger.info(self.vapi.ppcli("show ipsec"))

        for _, p in self.params.items():
            d = DpoProto.DPO_PROTO_IP6 if p.is_ipv6 else DpoProto.DPO_PROTO_IP4
            VppIpRoute(self,  p.remote_tun_if_host, p.addr_len,
                       [VppRoutePath(self.tun_if.remote_addr[p.addr_type],
                                     0xffffffff,
                                     proto=d)],
                       is_ip6=p.is_ipv6).add_vpp_config()

    def tearDown(self):
        super(TemplateIpsecEsp, self).tearDown()
        if not self.vpp_dead:
            self.vapi.cli("show hardware")


class TestIpsecEsp1(TemplateIpsecEsp, IpsecTra46Tests, IpsecTun46Tests):
    """ Ipsec ESP - TUN & TRA tests """
    tra4_encrypt_node_name = "esp4-encrypt"
    tra4_decrypt_node_name = "esp4-decrypt"
    tra6_encrypt_node_name = "esp6-encrypt"
    tra6_decrypt_node_name = "esp6-decrypt"
    tun4_encrypt_node_name = "esp4-encrypt"
    tun4_decrypt_node_name = "esp4-decrypt"
    tun6_encrypt_node_name = "esp6-encrypt"
    tun6_decrypt_node_name = "esp6-decrypt"


class TestIpsecEsp2(TemplateIpsecEsp, IpsecTcpTests):
    """ Ipsec ESP - TCP tests """
    pass


class TemplateIpsecEspUdp(TemplateIpsec):
    """
    UDP encapped ESP
    """
    def setUp(self):
        super(TemplateIpsecEspUdp, self).setUp()
        self.encryption_type = ESP
        self.tun_if = self.pg0
        self.tra_if = self.pg2
        self.logger.info(self.vapi.ppcli("show int addr"))

        p = self.ipv4_params
        p.flags = (VppEnum.vl_api_ipsec_sad_flags_t.
                   IPSEC_API_SAD_FLAG_UDP_ENCAP)
        p.nat_header = UDP(sport=5454, dport=4500)

        self.tra_spd = VppIpsecSpd(self, self.tra_spd_id)
        self.tra_spd.add_vpp_config()
        VppIpsecSpdItfBinding(self, self.tra_spd,
                              self.tra_if).add_vpp_config()

        config_esp_tra(self, p)
        config_tra_params(p, self.encryption_type)

        self.tun_spd = VppIpsecSpd(self, self.tun_spd_id)
        self.tun_spd.add_vpp_config()
        VppIpsecSpdItfBinding(self, self.tun_spd,
                              self.tun_if).add_vpp_config()

        config_esp_tun(self, p)
        self.logger.info(self.vapi.ppcli("show ipsec"))

        d = DpoProto.DPO_PROTO_IP4
        VppIpRoute(self,  p.remote_tun_if_host, p.addr_len,
                   [VppRoutePath(self.tun_if.remote_addr[p.addr_type],
                                 0xffffffff,
                                 proto=d)]).add_vpp_config()

    def tearDown(self):
        super(TemplateIpsecEspUdp, self).tearDown()
        if not self.vpp_dead:
            self.vapi.cli("show hardware")


class TestIpsecEspUdp(TemplateIpsecEspUdp, IpsecTra4Tests, IpsecTun4Tests):
    """ Ipsec NAT-T ESP UDP tests """
    tra4_encrypt_node_name = "esp4-encrypt"
    tra4_decrypt_node_name = "esp4-decrypt"
    tun4_encrypt_node_name = "esp4-encrypt"
    tun4_decrypt_node_name = "esp4-decrypt"
    pass


if __name__ == '__main__':
    unittest.main(testRunner=VppTestRunner)
er dispatch. */ #define VLIB_FRAME_FREE_AFTER_DISPATCH VLIB_NODE_FLAG_IS_PUNT /* Set when frame has traced packets. */ #define VLIB_FRAME_TRACE VLIB_NODE_FLAG_TRACE /* Number of vectors enqueue to this next since last overflow. */ u32 vectors_since_last_overflow; } vlib_next_frame_t; always_inline void vlib_next_frame_init (vlib_next_frame_t * nf) { clib_memset (nf, 0, sizeof (nf[0])); nf->node_runtime_index = ~0; } /* A frame pending dispatch by main loop. */ typedef struct { /* Node and runtime for this frame. */ u32 node_runtime_index; /* Frame index (in the heap). */ vlib_frame_t *frame; /* Start of next frames for this node. */ u32 next_frame_index; /* Special value for next_frame_index when there is no next frame. */ #define VLIB_PENDING_FRAME_NO_NEXT_FRAME ((u32) ~0) } vlib_pending_frame_t; typedef struct vlib_node_runtime_t { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); /**< cacheline mark */ vlib_node_function_t *function; /**< Node function to call. */ vlib_error_t *errors; /**< Vector of errors for this node. */ #if __SIZEOF_POINTER__ == 4 u8 pad[8]; #endif u32 clocks_since_last_overflow; /**< Number of clock cycles. */ u32 max_clock; /**< Maximum clock cycle for an invocation. */ u32 max_clock_n; /**< Number of vectors in the recorded max_clock. */ u32 calls_since_last_overflow; /**< Number of calls. */ u32 vectors_since_last_overflow; /**< Number of vector elements processed by this node. */ u32 perf_counter0_ticks_since_last_overflow; /**< Perf counter 0 ticks */ u32 perf_counter1_ticks_since_last_overflow; /**< Perf counter 1 ticks */ u32 perf_counter_vectors_since_last_overflow; /**< Perf counter vectors */ u32 next_frame_index; /**< Start of next frames for this node. */ u32 node_index; /**< Node index. */ u32 input_main_loops_per_call; /**< For input nodes: decremented on each main loop interation until it reaches zero and function is called. Allows some input nodes to be called more than others. */ u32 main_loop_count_last_dispatch; /**< Saved main loop counter of last dispatch of this node. */ u32 main_loop_vector_stats[2]; u16 flags; /**< Copy of main node flags. */ u16 state; /**< Input node state. */ u16 n_next_nodes; u16 cached_next_index; /**< Next frame index that vector arguments were last enqueued to last time this node ran. Set to zero before first run of this node. */ u16 thread_index; /**< thread this node runs on */ u8 runtime_data[0]; /**< Function dependent node-runtime data. This data is thread local, and it is not cloned from main thread. It needs to be initialized for each thread before it is used unless runtime_data template exists in vlib_node_t. */ } vlib_node_runtime_t; #define VLIB_NODE_RUNTIME_DATA_SIZE (sizeof (vlib_node_runtime_t) - STRUCT_OFFSET_OF (vlib_node_runtime_t, runtime_data)) typedef struct { /* Number of allocated frames for this scalar/vector size. */ u32 n_alloc_frames; /* Vector of free frames for this scalar/vector size. */ vlib_frame_t **free_frames; } vlib_frame_size_t; typedef struct { /* Users opaque value for event type. */ uword opaque; } vlib_process_event_type_t; typedef struct { /* Node runtime for this process. */ vlib_node_runtime_t node_runtime; /* Where to longjmp when process is done. */ clib_longjmp_t return_longjmp; #define VLIB_PROCESS_RETURN_LONGJMP_RETURN ((uword) ~0 - 0) #define VLIB_PROCESS_RETURN_LONGJMP_SUSPEND ((uword) ~0 - 1) /* Where to longjmp to resume node after suspend. */ clib_longjmp_t resume_longjmp; #define VLIB_PROCESS_RESUME_LONGJMP_SUSPEND 0 #define VLIB_PROCESS_RESUME_LONGJMP_RESUME 1 u16 flags; #define VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK (1 << 0) #define VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT (1 << 1) /* Set to indicate that this process has been added to resume vector. */ #define VLIB_PROCESS_RESUME_PENDING (1 << 2) /* Process function is currently running. */ #define VLIB_PROCESS_IS_RUNNING (1 << 3) /* Size of process stack. */ u16 log2_n_stack_bytes; u32 suspended_process_frame_index; /* Number of times this process was suspended. */ u32 n_suspends; /* Vectors of pending event data indexed by event type index. */ void **pending_event_data_by_type_index; /* Bitmap of event type-indices with non-empty vectors. */ uword *non_empty_event_type_bitmap; /* Bitmap of event type-indices which are one time events. */ uword *one_time_event_type_bitmap; /* Type is opaque pointer -- typically a pointer to an event handler function. Hash table to map opaque to a type index. */ uword *event_type_index_by_type_opaque; /* Pool of currently valid event types. */ vlib_process_event_type_t *event_type_pool; /* * When suspending saves clock time (10us ticks) when process * is to be resumed. */ u64 resume_clock_interval; /* Handle from timer code, to cancel an unexpired timer */ u32 stop_timer_handle; /* Default output function and its argument for any CLI outputs within the process. */ vlib_cli_output_function_t *output_function; uword output_function_arg; #ifdef CLIB_UNIX /* Pad to a multiple of the page size so we can mprotect process stacks */ #define PAGE_SIZE_MULTIPLE 0x1000 #define ALIGN_ON_MULTIPLE_PAGE_BOUNDARY_FOR_MPROTECT __attribute__ ((aligned (PAGE_SIZE_MULTIPLE))) #else #define ALIGN_ON_MULTIPLE_PAGE_BOUNDARY_FOR_MPROTECT #endif /* Process stack. Starts here and extends 2^log2_n_stack_bytes bytes. */ #define VLIB_PROCESS_STACK_MAGIC (0xdead7ead) u32 stack[0] ALIGN_ON_MULTIPLE_PAGE_BOUNDARY_FOR_MPROTECT; } vlib_process_t __attribute__ ((aligned (CLIB_CACHE_LINE_BYTES))); #ifdef CLIB_UNIX /* Ensure that the stack is aligned on the multiple of the page size */ typedef char assert_process_stack_must_be_aligned_exactly_to_page_size_multiple[(sizeof (vlib_process_t) - PAGE_SIZE_MULTIPLE) == 0 ? 0 : -1]; #endif typedef struct { u32 node_index; u32 one_time_event; } vlib_one_time_waiting_process_t; typedef struct { u16 n_data_elts; u16 n_data_elt_bytes; /* n_data_elts * n_data_elt_bytes */ u32 n_data_bytes; /* Process node & event type to be used to signal event. */ u32 process_node_index; u32 event_type_index; union { u8 inline_event_data[64 - 3 * sizeof (u32) - 2 * sizeof (u16)]; /* Vector of event data used only when data does not fit inline. */ u8 *event_data_as_vector; }; } vlib_signal_timed_event_data_t; always_inline uword vlib_timing_wheel_data_is_timed_event (u32 d) { return d & 1; } always_inline u32 vlib_timing_wheel_data_set_suspended_process (u32 i) { return 0 + 2 * i; } always_inline u32 vlib_timing_wheel_data_set_timed_event (u32 i) { return 1 + 2 * i; } always_inline uword vlib_timing_wheel_data_get_index (u32 d) { return d / 2; } typedef struct { /* Public nodes. */ vlib_node_t **nodes; /* Node index hashed by node name. */ uword *node_by_name; u32 flags; #define VLIB_NODE_MAIN_RUNTIME_STARTED (1 << 0) /* Nodes segregated by type for cache locality. Does not apply to nodes of type VLIB_NODE_TYPE_INTERNAL. */ vlib_node_runtime_t *nodes_by_type[VLIB_N_NODE_TYPE]; /* Node runtime indices for input nodes with pending interrupts. */ u32 *pending_interrupt_node_runtime_indices; clib_spinlock_t pending_interrupt_lock; /* Input nodes are switched from/to interrupt to/from polling mode when average vector length goes above/below polling/interrupt thresholds. */ u32 polling_threshold_vector_length; u32 interrupt_threshold_vector_length; /* Vector of next frames. */ vlib_next_frame_t *next_frames; /* Vector of internal node's frames waiting to be called. */ vlib_pending_frame_t *pending_frames; /* Timing wheel for scheduling time-based node dispatch. */ void *timing_wheel; vlib_signal_timed_event_data_t *signal_timed_event_data_pool; /* Opaque data vector added via timing_wheel_advance. */ u32 *data_from_advancing_timing_wheel; /* CPU time of next process to be ready on timing wheel. */ f64 time_next_process_ready; /* Vector of process nodes. One for each node of type VLIB_NODE_TYPE_PROCESS. */ vlib_process_t **processes; /* Current running process or ~0 if no process running. */ u32 current_process_index; /* Pool of pending process frames. */ vlib_pending_frame_t *suspended_process_frames; /* Vector of event data vectors pending recycle. */ void **recycled_event_data_vectors; /* Current counts of nodes in each state. */ u32 input_node_counts_by_state[VLIB_N_NODE_STATE]; /* Hash of (scalar_size,vector_size) to frame_sizes index. */ uword *frame_size_hash; /* Per-size frame allocation information. */ vlib_frame_size_t *frame_sizes; /* Time of last node runtime stats clear. */ f64 time_last_runtime_stats_clear; /* Node registrations added by constructors */ vlib_node_registration_t *node_registrations; } vlib_node_main_t; #define FRAME_QUEUE_MAX_NELTS 64 typedef struct { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); u64 head; u64 head_hint; u64 tail; u32 n_in_use; u32 nelts; u32 written; u32 threshold; i32 n_vectors[FRAME_QUEUE_MAX_NELTS]; } frame_queue_trace_t; typedef struct { u64 count[FRAME_QUEUE_MAX_NELTS]; } frame_queue_nelt_counter_t; #endif /* included_vlib_node_h */ /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "gnu") * End: */