From e11203e5b8fd61986573e0cba9e47cefcf50e60d Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Tue, 21 Sep 2021 12:34:19 +0000 Subject: ipsec: Record the number of packets lost from an SA Type: feature Gaps in the sequence numbers received on an SA indicate packets that were lost. Gaps are identified using the anti-replay window that records the sequences seen. Publish the number of lost packets in the stats segment at /net/ipsec/sa/lost Signed-off-by: Neale Ranns Change-Id: I8af1c09b7b25a705e18bf82e1623b3ce19e5a74d --- test/template_ipsec.py | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++ test/test_ipsec_esp.py | 3 ++ test/vpp_ipsec.py | 11 +++++++ 3 files changed, 101 insertions(+) (limited to 'test') diff --git a/test/template_ipsec.py b/test/template_ipsec.py index d5f13322a59..e4797353ecd 100644 --- a/test/template_ipsec.py +++ b/test/template_ipsec.py @@ -792,6 +792,87 @@ class IpsecTra4(object): p.scapy_tra_sa.seq_num = 351 p.vpp_tra_sa.seq_num = 351 + def verify_tra_lost(self): + p = self.params[socket.AF_INET] + esn_en = p.vpp_tra_sa.esn_en + + # + # send packets with seq numbers 1->34 + # this means the window size is still in Case B (see RFC4303 + # Appendix A) + # + # for reasons i haven't investigated Scapy won't create a packet with + # seq_num=0 + # + pkts = [(Ether(src=self.tra_if.remote_mac, + dst=self.tra_if.local_mac) / + p.scapy_tra_sa.encrypt(IP(src=self.tra_if.remote_ip4, + dst=self.tra_if.local_ip4) / + ICMP(), + seq_num=seq)) + for seq in range(1, 3)] + self.send_and_expect(self.tra_if, pkts, self.tra_if) + + self.assertEqual(p.tra_sa_out.get_lost(), 0) + + # skip a sequence number + pkts = [(Ether(src=self.tra_if.remote_mac, + dst=self.tra_if.local_mac) / + p.scapy_tra_sa.encrypt(IP(src=self.tra_if.remote_ip4, + dst=self.tra_if.local_ip4) / + ICMP(), + seq_num=seq)) + for seq in range(4, 6)] + self.send_and_expect(self.tra_if, pkts, self.tra_if) + + self.assertEqual(p.tra_sa_out.get_lost(), 0) + + # the lost packet are counted untill we get up past the first + # sizeof(replay_window) packets + pkts = [(Ether(src=self.tra_if.remote_mac, + dst=self.tra_if.local_mac) / + p.scapy_tra_sa.encrypt(IP(src=self.tra_if.remote_ip4, + dst=self.tra_if.local_ip4) / + ICMP(), + seq_num=seq)) + for seq in range(6, 100)] + self.send_and_expect(self.tra_if, pkts, self.tra_if) + + self.assertEqual(p.tra_sa_out.get_lost(), 1) + + # lost of holes in the sequence + pkts = [(Ether(src=self.tra_if.remote_mac, + dst=self.tra_if.local_mac) / + p.scapy_tra_sa.encrypt(IP(src=self.tra_if.remote_ip4, + dst=self.tra_if.local_ip4) / + ICMP(), + seq_num=seq)) + for seq in range(100, 200, 2)] + self.send_and_expect(self.tra_if, pkts, self.tra_if, n_rx=50) + + pkts = [(Ether(src=self.tra_if.remote_mac, + dst=self.tra_if.local_mac) / + p.scapy_tra_sa.encrypt(IP(src=self.tra_if.remote_ip4, + dst=self.tra_if.local_ip4) / + ICMP(), + seq_num=seq)) + for seq in range(200, 300)] + self.send_and_expect(self.tra_if, pkts, self.tra_if) + + self.assertEqual(p.tra_sa_out.get_lost(), 51) + + # a big hole in the seq number space + pkts = [(Ether(src=self.tra_if.remote_mac, + dst=self.tra_if.local_mac) / + p.scapy_tra_sa.encrypt(IP(src=self.tra_if.remote_ip4, + dst=self.tra_if.local_ip4) / + ICMP(), + seq_num=seq)) + for seq in range(400, 500)] + self.send_and_expect(self.tra_if, pkts, self.tra_if) + + self.assertEqual(p.tra_sa_out.get_lost(), 151) + def verify_tra_basic4(self, count=1, payload_size=54): """ ipsec v4 transport basic test """ self.vapi.cli("clear errors") @@ -826,6 +907,8 @@ class IpsecTra4(object): self.assertEqual(pkts, count, "incorrect SA out counts: expected %d != %d" % (count, pkts)) + self.assertEqual(p.tra_sa_out.get_lost(), 0) + self.assertEqual(p.tra_sa_in.get_lost(), 0) self.assert_packet_counter_equal(self.tra4_encrypt_node_name, count) self.assert_packet_counter_equal(self.tra4_decrypt_node_name[0], count) @@ -837,6 +920,10 @@ class IpsecTra4Tests(IpsecTra4): """ ipsec v4 transport anti-replay test """ self.verify_tra_anti_replay() + def test_tra_lost(self): + """ ipsec v4 transport lost packet test """ + self.verify_tra_lost() + def test_tra_basic(self, count=1): """ ipsec v4 transport basic test """ self.verify_tra_basic4(count=1) diff --git a/test/test_ipsec_esp.py b/test/test_ipsec_esp.py index 14112d6d71a..0e0aaee425c 100644 --- a/test/test_ipsec_esp.py +++ b/test/test_ipsec_esp.py @@ -974,6 +974,9 @@ class RunTestIpsecEspAll(ConfigIpsecESP, self.unconfig_network() self.config_network(self.params.values()) self.verify_hi_seq_num() + self.unconfig_network() + self.config_network(self.params.values()) + self.verify_tra_lost() # # swap the handlers while SAs are up diff --git a/test/vpp_ipsec.py b/test/vpp_ipsec.py index f9b7bc43752..76080e05c3a 100644 --- a/test/vpp_ipsec.py +++ b/test/vpp_ipsec.py @@ -313,6 +313,17 @@ class VppIpsecSA(VppObject): # +1 to skip main thread return c[worker+1][self.stat_index] + def get_lost(self, worker=None): + c = self.test.statistics.get_counter("/net/ipsec/sa/lost") + if worker is None: + total = 0 + for t in c: + total += t[self.stat_index] + return total + else: + # +1 to skip main thread + return c[worker+1][self.stat_index] + class VppIpsecTunProtect(VppObject): """ -- cgit 1.2.3-korg