From 72445c7d09a3206e0ace5ffaeb07aa7e13554af6 Mon Sep 17 00:00:00 2001 From: Timur Aitov Date: Tue, 24 Oct 2023 16:27:09 +0300 Subject: [PATCH] Add more autotests - firewall with resend fwsync - send fwsync to unicast - tun64 - firewall samples - acl gapped mask - balancer wlc scheduler - acl intersected gapped mask - balancer icmp - ruleset with 'table' - check RIB - nat64stateful --- .../050_firewall_state_resend/001-expect.pcap | Bin 0 -> 244 bytes .../050_firewall_state_resend/001-send.pcap | Bin 0 -> 106 bytes .../050_firewall_state_resend/002-expect.pcap | Bin 0 -> 106 bytes .../050_firewall_state_resend/002-send.pcap | Bin 0 -> 106 bytes .../050_firewall_state_resend/003-expect.pcap | Bin 0 -> 162 bytes .../050_firewall_state_resend/003-send.pcap | Bin 0 -> 24 bytes .../050_firewall_state_resend/004-expect.pcap | Bin 0 -> 24 bytes .../050_firewall_state_resend/004-send.pcap | Bin 0 -> 162 bytes .../050_firewall_state_resend/005-expect.pcap | Bin 0 -> 106 bytes .../050_firewall_state_resend/005-send.pcap | Bin 0 -> 106 bytes .../050_firewall_state_resend/006-expect.pcap | Bin 0 -> 162 bytes .../050_firewall_state_resend/006-send.pcap | Bin 0 -> 24 bytes .../050_firewall_state_resend/007-expect.pcap | Bin 0 -> 224 bytes .../050_firewall_state_resend/007-send.pcap | Bin 0 -> 86 bytes .../050_firewall_state_resend/008-expect.pcap | Bin 0 -> 86 bytes .../050_firewall_state_resend/008-send.pcap | Bin 0 -> 86 bytes .../050_firewall_state_resend/009-expect.pcap | Bin 0 -> 162 bytes .../050_firewall_state_resend/009-send.pcap | Bin 0 -> 24 bytes .../050_firewall_state_resend/010-expect.pcap | Bin 0 -> 24 bytes .../050_firewall_state_resend/010-send.pcap | Bin 0 -> 162 bytes .../050_firewall_state_resend/011-expect.pcap | Bin 0 -> 86 bytes .../050_firewall_state_resend/011-send.pcap | Bin 0 -> 86 bytes .../050_firewall_state_resend/012-expect.pcap | Bin 0 -> 162 bytes .../050_firewall_state_resend/012-send.pcap | Bin 0 -> 24 bytes .../050_firewall_state_resend/autotest.yaml | 61 + .../controlplane.conf | 64 + .../050_firewall_state_resend/firewall.txt | 7 + .../050_firewall_state_resend/gen.py | 200 ++ .../001-expect.pcap | Bin 0 -> 394 bytes .../001-send.pcap | Bin 0 -> 118 bytes .../002-expect.pcap | Bin 0 -> 24 bytes .../002-send.pcap | Bin 0 -> 162 bytes .../003-expect.pcap | Bin 0 -> 118 bytes .../003-send.pcap | Bin 0 -> 118 bytes .../004-expect.pcap | Bin 0 -> 374 bytes .../004-send.pcap | Bin 0 -> 98 bytes .../005-expect.pcap | Bin 0 -> 24 bytes .../005-send.pcap | Bin 0 -> 162 bytes .../006-expect.pcap | Bin 0 -> 98 bytes .../006-send.pcap | Bin 0 -> 98 bytes .../007-expect-tcp.pcap | Bin 0 -> 588 bytes .../007-expect-tech.pcap | Bin 0 -> 300 bytes .../007-send.pcap | Bin 0 -> 588 bytes .../autotest.yaml | 38 + .../controlplane.conf | 67 + .../firewall.txt | 7 + .../gen.py | 178 ++ .../001_one_port/051_tun64/autotest.yaml | 15 + .../001_one_port/051_tun64/controlplane.conf | 91 + .../units/001_one_port/051_tun64/decap.pcap | Bin 0 -> 228 bytes .../001_one_port/051_tun64/decap_expect.pcap | Bin 0 -> 148 bytes .../units/001_one_port/051_tun64/encap.pcap | Bin 0 -> 148 bytes .../001_one_port/051_tun64/encap_expect.pcap | Bin 0 -> 126 bytes .../001_one_port/051_tun64/encap_rnd.pcap | Bin 0 -> 148 bytes .../051_tun64/encap_rnd_expect.pcap | Bin 0 -> 228 bytes autotest/units/001_one_port/051_tun64/gen.py | 42 + .../001_one_port/051_tun64/map64_rndsrc.json | 14 + .../052_firewall_samples/001-expect.pcap | Bin 0 -> 400 bytes .../052_firewall_samples/001-send.pcap | Bin 0 -> 588 bytes .../052_firewall_samples/002-expect.pcap | Bin 0 -> 320 bytes .../052_firewall_samples/002-send.pcap | Bin 0 -> 468 bytes .../052_firewall_samples/autotest.yaml | 23 + .../052_firewall_samples/controlplane.conf | 43 + .../052_firewall_samples/firewall.txt | 7 + .../001_one_port/052_firewall_samples/gen.py | 68 + .../052_firewall_samples/samples.json | 7 + .../053_firewall_defaults/001-expect.pcap | Bin 0 -> 282 bytes .../053_firewall_defaults/001-send.pcap | Bin 0 -> 282 bytes .../053_firewall_defaults/autotest.yaml | 7 + .../053_firewall_defaults/controlplane.conf | 42 + .../053_firewall_defaults/firewall.txt | 2 + .../001_one_port/053_firewall_defaults/gen.py | 44 + .../054_gapped_masks_112/001-expect.pcap | Bin 0 -> 118 bytes .../054_gapped_masks_112/001-send.pcap | Bin 0 -> 118 bytes .../054_gapped_masks_112/autotest.yaml | 7 + .../054_gapped_masks_112/controlplane.conf | 46 + .../054_gapped_masks_112/firewall.txt | 7 + .../001_one_port/054_gapped_masks_112/gen.py | 39 + .../055_balancer_wlc/001-expect.pcap | Bin 0 -> 3672 bytes .../055_balancer_wlc/001-send.pcap | Bin 0 -> 2392 bytes .../055_balancer_wlc/002-expect.pcap | Bin 0 -> 3672 bytes .../055_balancer_wlc/002-send.pcap | Bin 0 -> 2392 bytes .../055_balancer_wlc/003-expect.pcap | Bin 0 -> 3672 bytes .../055_balancer_wlc/003-send.pcap | Bin 0 -> 2392 bytes .../055_balancer_wlc/autotest.yaml | 50 + .../055_balancer_wlc/controlplane.conf | 47 + .../001_one_port/055_balancer_wlc/gen.py | 33 + .../055_balancer_wlc/services.conf | 30 + .../055_two_rule_three_ids/001-expect.pcap | Bin 0 -> 400 bytes .../055_two_rule_three_ids/001-send.pcap | Bin 0 -> 776 bytes .../055_two_rule_three_ids/autotest.yaml | 7 + .../055_two_rule_three_ids/controlplane.conf | 46 + .../055_two_rule_three_ids/firewall.txt | 7 + .../055_two_rule_three_ids/gen.py | 53 + .../001-expect.pcap | Bin 0 -> 1281024 bytes .../001-send.pcap | Bin 0 -> 1071024 bytes .../autotest.yaml | 24 + .../controlplane.conf | 53 + .../056_balancer_icmp_rate_limit/gen.py | 34 + .../services.conf | 14 + .../056_balancer_icmp_rate_limit/unrdup.cfg | 1 + .../001-expect.pcap | Bin 0 -> 184 bytes .../056_balancer_vs_ping_reply/001-send.pcap | Bin 0 -> 184 bytes .../002-expect.pcap | Bin 0 -> 224 bytes .../056_balancer_vs_ping_reply/002-send.pcap | Bin 0 -> 224 bytes .../003-expect.pcap | Bin 0 -> 122 bytes .../056_balancer_vs_ping_reply/003-send.pcap | Bin 0 -> 122 bytes .../056_balancer_vs_ping_reply/autotest.yaml | 57 + .../controlplane.conf | 49 + .../056_balancer_vs_ping_reply/gen.py | 43 + .../056_balancer_vs_ping_reply/services.conf | 62 + .../056_multi_cross_rules/001-expect.pcap | Bin 0 -> 5006 bytes .../056_multi_cross_rules/001-send.pcap | Bin 0 -> 13560 bytes .../056_multi_cross_rules/autotest.yaml | 7 + .../056_multi_cross_rules/controlplane.conf | 46 + .../056_multi_cross_rules/firewall.txt | 12 + .../001_one_port/056_multi_cross_rules/gen.py | 128 + .../057_self_cross_rules/001-expect.pcap | Bin 0 -> 964 bytes .../057_self_cross_rules/001-send.pcap | Bin 0 -> 3408 bytes .../057_self_cross_rules/autotest.yaml | 7 + .../057_self_cross_rules/controlplane.conf | 46 + .../057_self_cross_rules/firewall.txt | 7 + .../001_one_port/057_self_cross_rules/gen.py | 69 + .../001-expect.pcap | Bin 0 -> 868 bytes .../001-send.pcap | Bin 0 -> 1606 bytes .../autotest.yaml | 7 + .../controlplane.conf | 46 + .../firewall.txt | 27 + .../058_network_intersect_extended/gen.py | 89 + .../059_firewall_tablearg/001-expect.pcap | Bin 0 -> 606 bytes .../059_firewall_tablearg/001-send.pcap | Bin 0 -> 1260 bytes .../059_firewall_tablearg/autotest.yaml | 7 + .../059_firewall_tablearg/controlplane.conf | 43 + .../059_firewall_tablearg/firewall.conf.txt | 39 + .../001_one_port/059_firewall_tablearg/gen.py | 45 + .../059_firewall_via_tablearg/001-expect.pcap | Bin 0 -> 1100 bytes .../059_firewall_via_tablearg/001-send.pcap | Bin 0 -> 1236 bytes .../059_firewall_via_tablearg/autotest.yaml | 10 + .../controlplane.conf | 69 + .../firewall.conf.txt | 24 + .../059_firewall_via_tablearg/gen.py | 52 + .../001_one_port/059_rib/001-expect.pcap | Bin 0 -> 336 bytes .../units/001_one_port/059_rib/001-send.pcap | Bin 0 -> 320 bytes .../001_one_port/059_rib/002-expect.pcap | Bin 0 -> 336 bytes .../units/001_one_port/059_rib/002-send.pcap | Bin 0 -> 320 bytes .../units/001_one_port/059_rib/autotest.yaml | 2265 +++++++++++++++++ .../001_one_port/059_rib/controlplane.conf | 32 + autotest/units/001_one_port/059_rib/gen.py | 48 + .../001-expect.pcap | Bin 0 -> 2606 bytes .../060_firewall_inplace_rules/001-send.pcap | Bin 0 -> 2848 bytes .../060_firewall_inplace_rules/autotest.yaml | 7 + .../controlplane.conf | 47 + .../060_firewall_inplace_rules/gen.py | 47 + .../061_nat64stateful/001-expect.pcap | Bin 0 -> 690 bytes .../061_nat64stateful/001-send.pcap | Bin 0 -> 870 bytes .../061_nat64stateful/002-expect.pcap | Bin 0 -> 776 bytes .../061_nat64stateful/002-send.pcap | Bin 0 -> 1208 bytes .../061_nat64stateful/003-expect.pcap | Bin 0 -> 394 bytes .../061_nat64stateful/003-send.pcap | Bin 0 -> 494 bytes .../061_nat64stateful/004-expect.pcap | Bin 0 -> 494 bytes .../061_nat64stateful/004-send.pcap | Bin 0 -> 394 bytes .../061_nat64stateful/005-expect.pcap | Bin 0 -> 98 bytes .../061_nat64stateful/005-send.pcap | Bin 0 -> 8580 bytes .../061_nat64stateful/006-expect.pcap | Bin 0 -> 24 bytes .../061_nat64stateful/006-send.pcap | Bin 0 -> 8226 bytes .../061_nat64stateful/007-expect.pcap | Bin 0 -> 107 bytes .../061_nat64stateful/007-send.pcap | Bin 0 -> 218 bytes .../061_nat64stateful/008-expect.pcap | Bin 0 -> 127 bytes .../061_nat64stateful/008-send.pcap | Bin 0 -> 427 bytes .../061_nat64stateful/009-expect.pcap | Bin 0 -> 24 bytes .../061_nat64stateful/009-send.pcap | Bin 0 -> 738 bytes .../061_nat64stateful/010-expect.pcap | Bin 0 -> 306 bytes .../061_nat64stateful/010-send.pcap | Bin 0 -> 2682 bytes .../061_nat64stateful/011-expect.pcap | Bin 0 -> 24 bytes .../061_nat64stateful/011-send.pcap | Bin 0 -> 1016 bytes .../061_nat64stateful/012-expect.pcap | Bin 0 -> 520 bytes .../061_nat64stateful/012-send.pcap | Bin 0 -> 680 bytes .../061_nat64stateful/013-expect.pcap | Bin 0 -> 680 bytes .../061_nat64stateful/013-send.pcap | Bin 0 -> 1016 bytes .../061_nat64stateful/014-expect.pcap | Bin 0 -> 773 bytes .../061_nat64stateful/014-send.pcap | Bin 0 -> 973 bytes .../061_nat64stateful/015-expect.pcap | Bin 0 -> 973 bytes .../061_nat64stateful/015-send.pcap | Bin 0 -> 773 bytes .../061_nat64stateful/autotest.yaml | 117 + .../061_nat64stateful/controlplane.conf | 55 + .../001_one_port/061_nat64stateful/gen.py | 325 +++ .../001-expect.pcap | Bin 0 -> 37912 bytes .../062_nat64stateful_multipool/001-send.pcap | Bin 0 -> 48246 bytes .../002-expect.pcap | Bin 0 -> 48152 bytes .../062_nat64stateful_multipool/002-send.pcap | Bin 0 -> 75800 bytes .../003-expect.pcap | Bin 0 -> 151576 bytes .../062_nat64stateful_multipool/003-send.pcap | Bin 0 -> 192536 bytes .../004-expect.pcap | Bin 0 -> 616 bytes .../062_nat64stateful_multipool/004-send.pcap | Bin 0 -> 776 bytes .../005-expect.pcap | Bin 0 -> 776 bytes .../062_nat64stateful_multipool/005-send.pcap | Bin 0 -> 616 bytes .../062_nat64stateful_multipool/autotest.yaml | 23 + .../controlplane.conf | 61 + .../062_nat64stateful_multipool/gen.py | 68 + .../001-expect.pcap | Bin 0 -> 284184 bytes .../001-send.pcap | Bin 0 -> 360984 bytes .../002-expect.pcap | Bin 0 -> 72216 bytes .../002-send.pcap | Bin 0 -> 56856 bytes .../003-expect.pcap | Bin 0 -> 227352 bytes .../003-send.pcap | Bin 0 -> 288792 bytes .../autotest.yaml | 15 + .../controlplane.conf | 78 + .../063_nat64stateful_multimodule/gen.py | 78 + .../001-expect.pcap | Bin 0 -> 616 bytes .../001-send.pcap | Bin 0 -> 776 bytes .../002-expect.pcap | Bin 0 -> 1296 bytes .../002-send.pcap | Bin 0 -> 1152 bytes .../autotest.yaml | 127 + .../controlplane.conf | 67 + .../064_nat64stateful_egresstunnel/gen.py | 75 + 215 files changed, 6051 insertions(+) create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/001-expect.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/001-send.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/002-expect.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/002-send.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/003-expect.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/003-send.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/004-expect.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/004-send.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/005-expect.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/005-send.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/006-expect.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/006-send.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/007-expect.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/007-send.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/008-expect.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/008-send.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/009-expect.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/009-send.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/010-expect.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/010-send.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/011-expect.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/011-send.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/012-expect.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/012-send.pcap create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/autotest.yaml create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/controlplane.conf create mode 100644 autotest/units/001_one_port/050_firewall_state_resend/firewall.txt create mode 100755 autotest/units/001_one_port/050_firewall_state_resend/gen.py create mode 100644 autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/001-expect.pcap create mode 100644 autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/001-send.pcap create mode 100644 autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/002-expect.pcap create mode 100644 autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/002-send.pcap create mode 100644 autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/003-expect.pcap create mode 100644 autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/003-send.pcap create mode 100644 autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/004-expect.pcap create mode 100644 autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/004-send.pcap create mode 100644 autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/005-expect.pcap create mode 100644 autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/005-send.pcap create mode 100644 autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/006-expect.pcap create mode 100644 autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/006-send.pcap create mode 100644 autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/007-expect-tcp.pcap create mode 100644 autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/007-expect-tech.pcap create mode 100644 autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/007-send.pcap create mode 100644 autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/autotest.yaml create mode 100644 autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/controlplane.conf create mode 100644 autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/firewall.txt create mode 100755 autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/gen.py create mode 100644 autotest/units/001_one_port/051_tun64/autotest.yaml create mode 100644 autotest/units/001_one_port/051_tun64/controlplane.conf create mode 100644 autotest/units/001_one_port/051_tun64/decap.pcap create mode 100644 autotest/units/001_one_port/051_tun64/decap_expect.pcap create mode 100644 autotest/units/001_one_port/051_tun64/encap.pcap create mode 100644 autotest/units/001_one_port/051_tun64/encap_expect.pcap create mode 100644 autotest/units/001_one_port/051_tun64/encap_rnd.pcap create mode 100644 autotest/units/001_one_port/051_tun64/encap_rnd_expect.pcap create mode 100755 autotest/units/001_one_port/051_tun64/gen.py create mode 100644 autotest/units/001_one_port/051_tun64/map64_rndsrc.json create mode 100644 autotest/units/001_one_port/052_firewall_samples/001-expect.pcap create mode 100644 autotest/units/001_one_port/052_firewall_samples/001-send.pcap create mode 100644 autotest/units/001_one_port/052_firewall_samples/002-expect.pcap create mode 100644 autotest/units/001_one_port/052_firewall_samples/002-send.pcap create mode 100644 autotest/units/001_one_port/052_firewall_samples/autotest.yaml create mode 100644 autotest/units/001_one_port/052_firewall_samples/controlplane.conf create mode 100644 autotest/units/001_one_port/052_firewall_samples/firewall.txt create mode 100755 autotest/units/001_one_port/052_firewall_samples/gen.py create mode 100644 autotest/units/001_one_port/052_firewall_samples/samples.json create mode 100644 autotest/units/001_one_port/053_firewall_defaults/001-expect.pcap create mode 100644 autotest/units/001_one_port/053_firewall_defaults/001-send.pcap create mode 100644 autotest/units/001_one_port/053_firewall_defaults/autotest.yaml create mode 100644 autotest/units/001_one_port/053_firewall_defaults/controlplane.conf create mode 100644 autotest/units/001_one_port/053_firewall_defaults/firewall.txt create mode 100755 autotest/units/001_one_port/053_firewall_defaults/gen.py create mode 100644 autotest/units/001_one_port/054_gapped_masks_112/001-expect.pcap create mode 100644 autotest/units/001_one_port/054_gapped_masks_112/001-send.pcap create mode 100644 autotest/units/001_one_port/054_gapped_masks_112/autotest.yaml create mode 100644 autotest/units/001_one_port/054_gapped_masks_112/controlplane.conf create mode 100644 autotest/units/001_one_port/054_gapped_masks_112/firewall.txt create mode 100755 autotest/units/001_one_port/054_gapped_masks_112/gen.py create mode 100644 autotest/units/001_one_port/055_balancer_wlc/001-expect.pcap create mode 100644 autotest/units/001_one_port/055_balancer_wlc/001-send.pcap create mode 100644 autotest/units/001_one_port/055_balancer_wlc/002-expect.pcap create mode 100644 autotest/units/001_one_port/055_balancer_wlc/002-send.pcap create mode 100644 autotest/units/001_one_port/055_balancer_wlc/003-expect.pcap create mode 100644 autotest/units/001_one_port/055_balancer_wlc/003-send.pcap create mode 100644 autotest/units/001_one_port/055_balancer_wlc/autotest.yaml create mode 100644 autotest/units/001_one_port/055_balancer_wlc/controlplane.conf create mode 100755 autotest/units/001_one_port/055_balancer_wlc/gen.py create mode 100644 autotest/units/001_one_port/055_balancer_wlc/services.conf create mode 100644 autotest/units/001_one_port/055_two_rule_three_ids/001-expect.pcap create mode 100644 autotest/units/001_one_port/055_two_rule_three_ids/001-send.pcap create mode 100644 autotest/units/001_one_port/055_two_rule_three_ids/autotest.yaml create mode 100644 autotest/units/001_one_port/055_two_rule_three_ids/controlplane.conf create mode 100644 autotest/units/001_one_port/055_two_rule_three_ids/firewall.txt create mode 100755 autotest/units/001_one_port/055_two_rule_three_ids/gen.py create mode 100644 autotest/units/001_one_port/056_balancer_icmp_rate_limit/001-expect.pcap create mode 100644 autotest/units/001_one_port/056_balancer_icmp_rate_limit/001-send.pcap create mode 100644 autotest/units/001_one_port/056_balancer_icmp_rate_limit/autotest.yaml create mode 100644 autotest/units/001_one_port/056_balancer_icmp_rate_limit/controlplane.conf create mode 100755 autotest/units/001_one_port/056_balancer_icmp_rate_limit/gen.py create mode 100644 autotest/units/001_one_port/056_balancer_icmp_rate_limit/services.conf create mode 100644 autotest/units/001_one_port/056_balancer_icmp_rate_limit/unrdup.cfg create mode 100644 autotest/units/001_one_port/056_balancer_vs_ping_reply/001-expect.pcap create mode 100644 autotest/units/001_one_port/056_balancer_vs_ping_reply/001-send.pcap create mode 100644 autotest/units/001_one_port/056_balancer_vs_ping_reply/002-expect.pcap create mode 100644 autotest/units/001_one_port/056_balancer_vs_ping_reply/002-send.pcap create mode 100644 autotest/units/001_one_port/056_balancer_vs_ping_reply/003-expect.pcap create mode 100644 autotest/units/001_one_port/056_balancer_vs_ping_reply/003-send.pcap create mode 100644 autotest/units/001_one_port/056_balancer_vs_ping_reply/autotest.yaml create mode 100644 autotest/units/001_one_port/056_balancer_vs_ping_reply/controlplane.conf create mode 100755 autotest/units/001_one_port/056_balancer_vs_ping_reply/gen.py create mode 100644 autotest/units/001_one_port/056_balancer_vs_ping_reply/services.conf create mode 100644 autotest/units/001_one_port/056_multi_cross_rules/001-expect.pcap create mode 100644 autotest/units/001_one_port/056_multi_cross_rules/001-send.pcap create mode 100644 autotest/units/001_one_port/056_multi_cross_rules/autotest.yaml create mode 100644 autotest/units/001_one_port/056_multi_cross_rules/controlplane.conf create mode 100644 autotest/units/001_one_port/056_multi_cross_rules/firewall.txt create mode 100755 autotest/units/001_one_port/056_multi_cross_rules/gen.py create mode 100644 autotest/units/001_one_port/057_self_cross_rules/001-expect.pcap create mode 100644 autotest/units/001_one_port/057_self_cross_rules/001-send.pcap create mode 100644 autotest/units/001_one_port/057_self_cross_rules/autotest.yaml create mode 100644 autotest/units/001_one_port/057_self_cross_rules/controlplane.conf create mode 100644 autotest/units/001_one_port/057_self_cross_rules/firewall.txt create mode 100755 autotest/units/001_one_port/057_self_cross_rules/gen.py create mode 100644 autotest/units/001_one_port/058_network_intersect_extended/001-expect.pcap create mode 100644 autotest/units/001_one_port/058_network_intersect_extended/001-send.pcap create mode 100644 autotest/units/001_one_port/058_network_intersect_extended/autotest.yaml create mode 100644 autotest/units/001_one_port/058_network_intersect_extended/controlplane.conf create mode 100644 autotest/units/001_one_port/058_network_intersect_extended/firewall.txt create mode 100755 autotest/units/001_one_port/058_network_intersect_extended/gen.py create mode 100644 autotest/units/001_one_port/059_firewall_tablearg/001-expect.pcap create mode 100644 autotest/units/001_one_port/059_firewall_tablearg/001-send.pcap create mode 100644 autotest/units/001_one_port/059_firewall_tablearg/autotest.yaml create mode 100644 autotest/units/001_one_port/059_firewall_tablearg/controlplane.conf create mode 100644 autotest/units/001_one_port/059_firewall_tablearg/firewall.conf.txt create mode 100755 autotest/units/001_one_port/059_firewall_tablearg/gen.py create mode 100644 autotest/units/001_one_port/059_firewall_via_tablearg/001-expect.pcap create mode 100644 autotest/units/001_one_port/059_firewall_via_tablearg/001-send.pcap create mode 100644 autotest/units/001_one_port/059_firewall_via_tablearg/autotest.yaml create mode 100644 autotest/units/001_one_port/059_firewall_via_tablearg/controlplane.conf create mode 100644 autotest/units/001_one_port/059_firewall_via_tablearg/firewall.conf.txt create mode 100755 autotest/units/001_one_port/059_firewall_via_tablearg/gen.py create mode 100644 autotest/units/001_one_port/059_rib/001-expect.pcap create mode 100644 autotest/units/001_one_port/059_rib/001-send.pcap create mode 100644 autotest/units/001_one_port/059_rib/002-expect.pcap create mode 100644 autotest/units/001_one_port/059_rib/002-send.pcap create mode 100644 autotest/units/001_one_port/059_rib/autotest.yaml create mode 100644 autotest/units/001_one_port/059_rib/controlplane.conf create mode 100644 autotest/units/001_one_port/059_rib/gen.py create mode 100644 autotest/units/001_one_port/060_firewall_inplace_rules/001-expect.pcap create mode 100644 autotest/units/001_one_port/060_firewall_inplace_rules/001-send.pcap create mode 100644 autotest/units/001_one_port/060_firewall_inplace_rules/autotest.yaml create mode 100644 autotest/units/001_one_port/060_firewall_inplace_rules/controlplane.conf create mode 100755 autotest/units/001_one_port/060_firewall_inplace_rules/gen.py create mode 100644 autotest/units/001_one_port/061_nat64stateful/001-expect.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/001-send.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/002-expect.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/002-send.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/003-expect.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/003-send.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/004-expect.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/004-send.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/005-expect.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/005-send.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/006-expect.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/006-send.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/007-expect.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/007-send.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/008-expect.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/008-send.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/009-expect.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/009-send.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/010-expect.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/010-send.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/011-expect.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/011-send.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/012-expect.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/012-send.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/013-expect.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/013-send.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/014-expect.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/014-send.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/015-expect.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/015-send.pcap create mode 100644 autotest/units/001_one_port/061_nat64stateful/autotest.yaml create mode 100644 autotest/units/001_one_port/061_nat64stateful/controlplane.conf create mode 100755 autotest/units/001_one_port/061_nat64stateful/gen.py create mode 100644 autotest/units/001_one_port/062_nat64stateful_multipool/001-expect.pcap create mode 100644 autotest/units/001_one_port/062_nat64stateful_multipool/001-send.pcap create mode 100644 autotest/units/001_one_port/062_nat64stateful_multipool/002-expect.pcap create mode 100644 autotest/units/001_one_port/062_nat64stateful_multipool/002-send.pcap create mode 100644 autotest/units/001_one_port/062_nat64stateful_multipool/003-expect.pcap create mode 100644 autotest/units/001_one_port/062_nat64stateful_multipool/003-send.pcap create mode 100644 autotest/units/001_one_port/062_nat64stateful_multipool/004-expect.pcap create mode 100644 autotest/units/001_one_port/062_nat64stateful_multipool/004-send.pcap create mode 100644 autotest/units/001_one_port/062_nat64stateful_multipool/005-expect.pcap create mode 100644 autotest/units/001_one_port/062_nat64stateful_multipool/005-send.pcap create mode 100644 autotest/units/001_one_port/062_nat64stateful_multipool/autotest.yaml create mode 100644 autotest/units/001_one_port/062_nat64stateful_multipool/controlplane.conf create mode 100755 autotest/units/001_one_port/062_nat64stateful_multipool/gen.py create mode 100644 autotest/units/001_one_port/063_nat64stateful_multimodule/001-expect.pcap create mode 100644 autotest/units/001_one_port/063_nat64stateful_multimodule/001-send.pcap create mode 100644 autotest/units/001_one_port/063_nat64stateful_multimodule/002-expect.pcap create mode 100644 autotest/units/001_one_port/063_nat64stateful_multimodule/002-send.pcap create mode 100644 autotest/units/001_one_port/063_nat64stateful_multimodule/003-expect.pcap create mode 100644 autotest/units/001_one_port/063_nat64stateful_multimodule/003-send.pcap create mode 100644 autotest/units/001_one_port/063_nat64stateful_multimodule/autotest.yaml create mode 100644 autotest/units/001_one_port/063_nat64stateful_multimodule/controlplane.conf create mode 100755 autotest/units/001_one_port/063_nat64stateful_multimodule/gen.py create mode 100644 autotest/units/001_one_port/064_nat64stateful_egresstunnel/001-expect.pcap create mode 100644 autotest/units/001_one_port/064_nat64stateful_egresstunnel/001-send.pcap create mode 100644 autotest/units/001_one_port/064_nat64stateful_egresstunnel/002-expect.pcap create mode 100644 autotest/units/001_one_port/064_nat64stateful_egresstunnel/002-send.pcap create mode 100644 autotest/units/001_one_port/064_nat64stateful_egresstunnel/autotest.yaml create mode 100644 autotest/units/001_one_port/064_nat64stateful_egresstunnel/controlplane.conf create mode 100755 autotest/units/001_one_port/064_nat64stateful_egresstunnel/gen.py diff --git a/autotest/units/001_one_port/050_firewall_state_resend/001-expect.pcap b/autotest/units/001_one_port/050_firewall_state_resend/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..0641abe4c8dad411fad4401ba04dbe1365583e98 GIT binary patch literal 244 zcmca|c+)~A1{MYw`2U}Qff2}Y+-ja`t;5gY1Z0CS5C{qiG6*UeyM#6}Fr>8IO#q2; z2-*t@Dk*`OP{635za49fumXrY@#kdLlsa0gpG}X1S8Bu_6txG9RwZz pH2`H0;NyQL1P91s)Vr;Bo5A7ja+s(o1JDD43~cB&qq_{I9sq5YB18ZH literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/001-send.pcap b/autotest/units/001_one_port/050_firewall_state_resend/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..2ab2c20d9706006aecd9e092fe1da5198f187534 GIT binary patch literal 106 zcmca|c+)~A1{MYw`2U}Qff2}Y+-jb>T7#d#3CIRv20iyz;L4NZURV@ gL(oA`P)P~IgaSqd1>U>=WfTlxe4yE;3>?*301-YAl>h($ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/002-expect.pcap b/autotest/units/001_one_port/050_firewall_state_resend/002-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..c50cb70218a0b2f03304803687687a8179abd38f GIT binary patch literal 106 zcmca|c+)~A1{MYw`2U}Qff2}Y+-jcs!Gxc|3CIRvAP^K3WDry`b_s1{U`T1Zn*b8y g5VRK*R8j&lp@30Af%ooz83h9vA858I14p$M00r9+P5=M^ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/002-send.pcap b/autotest/units/001_one_port/050_firewall_state_resend/002-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a201cfcfcc034b53e97e801aecd1027aba694ee2 GIT binary patch literal 106 zcmca|c+)~A1{MYw`2U}Qff2}Y+-jcs#gL!D3CIRv20iyz;L4NZURV@ gL(oA`P)P~IgaSqd1>U>=WfTlxe4yE;3>?*304gyM=Kufz literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/003-expect.pcap b/autotest/units/001_one_port/050_firewall_state_resend/003-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..49563ecc5521d8a109fee438b34eba2d6ea1d8d5 GIT binary patch literal 162 zcmca|c+)~A1{MYw`2U}Qff2}Y+-jc6Y0b}21!RM;u`!TfWDry`b_s1{V876IHvuTX z;2`MmuK~n>gOC52;A{|sQSY|iZ3c(8%VDCX3_$Ay8Q2sQc<=s~Q80jtGYSeSDZ$i$ H^ugEwB(WEN literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/003-send.pcap b/autotest/units/001_one_port/050_firewall_state_resend/003-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a324304509bdd12aef4a69458a409cefefafe614 GIT binary patch literal 24 Ycmca|c+)~A1{MYw`2U}Qff2|708wKE@Bjb+ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/004-expect.pcap b/autotest/units/001_one_port/050_firewall_state_resend/004-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a324304509bdd12aef4a69458a409cefefafe614 GIT binary patch literal 24 Ycmca|c+)~A1{MYw`2U}Qff2|708wKE@Bjb+ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/004-send.pcap b/autotest/units/001_one_port/050_firewall_state_resend/004-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..1c4e37973034b08a6ffe0d60940d0ef7849ecda7 GIT binary patch literal 162 zcmca|c+)~A1{MYw`2U}Qff2}Y+-ja0ZO6}01!RM;u`!SUNf;X&H!`qaXuF#LD#XN~!63-Mrl7!k_rHvS0aRQ-P*6z;rUpn0 Gz}Nug0v2un literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/005-expect.pcap b/autotest/units/001_one_port/050_firewall_state_resend/005-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..724f47fd70549a1a15933c5f7061e156cf4bf306 GIT binary patch literal 106 zcmca|c+)~A1{MYw`2U}Qff2}Y+G?IUg9%83*bqrUK|uyVC1aP+Mh1qIwz~-+Q4T?S g1qI%_|78>mAc`0S1O=6ppllE&z$ByrR2Qlb0Q}4kwg3PC literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/005-send.pcap b/autotest/units/001_one_port/050_firewall_state_resend/005-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a9ccbde6d2373b002d3925eedf44bc08f970a05b GIT binary patch literal 106 zcmca|c+)~A1{MYw`2U}Qff2}Y+-jaG?8MLD1Z0CSgP@YJODK?5Qc`MUU^vlsHvuHd iA?To>z>=N3@z<#0aZURt% z!9mdBUjv8%2Os}4!Py`Nquy=3+YAl@DKJqXCI$@#K?XJj1>U>=WfTmc;sSz#N=h&_ JKw1FC1^^F+7S8|x literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/006-send.pcap b/autotest/units/001_one_port/050_firewall_state_resend/006-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a324304509bdd12aef4a69458a409cefefafe614 GIT binary patch literal 24 Ycmca|c+)~A1{MYw`2U}Qff2|708wKE@Bjb+ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/007-expect.pcap b/autotest/units/001_one_port/050_firewall_state_resend/007-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..65a1e1f8875af66f19f0f7f9ed408b81be0de8fe GIT binary patch literal 224 zcmca|c+)~A1{MYw`2U}Qff2}Y+G?Kqkeh))56A{#AW%|LVh~g^b_s1{U^v0S;L5-t z15#=)n17B7s0jp^Uoe<5aJ=6K(*2r;fuRbh4TO!2fdnH=H~WRQy9q!61_wche+?i8 m9DMxG1ZRU7jC!~AZZkMksew!f*<#A@f|)@O$-yYfF*yJZF&~Qn literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/007-send.pcap b/autotest/units/001_one_port/050_firewall_state_resend/007-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..452db8d25d1895a8b925c3ad50f33c848a030bbe GIT binary patch literal 86 zcmca|c+)~A1{MYw`2U}Qff2}Y+G?I^!^yy)2V{dVgP@YJODKpI6l`Q*Na0{`Wnhp2 XDRmIcJI4jo1Om)27)%*B-tPkdg~tvS literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/008-expect.pcap b/autotest/units/001_one_port/050_firewall_state_resend/008-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..4613f888f79d9ac901b703ef9e715cd1d4ed9be1 GIT binary patch literal 86 zcmca|c+)~A1{MYw`2U}Qff2}Y+G?IUO_+f}56A{#AW%|LVh~g^b_s1{U^v0S;L5-t Y15#=)n17B7s0jp^Uoe<5aJ=6K0IU@c5dZ)H literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/008-send.pcap b/autotest/units/001_one_port/050_firewall_state_resend/008-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..ed4a3ab3b09b6bb65532b777bdcc369826188c91 GIT binary patch literal 86 zcmca|c+)~A1{MYw`2U}Qff2}Y+G?IEEXcs12V{dVgP@YJODKpI6l`Q*Na0{`Wnhp2 XDRmIcJI4jo1Om)27)%*B-tPkdenk!S literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/009-expect.pcap b/autotest/units/001_one_port/050_firewall_state_resend/009-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..de796eee030bb2588d956ad99161ce7bcbd843e2 GIT binary patch literal 162 zcmca|c+)~A1{MYw`2U}Qff2}Y+G?JfEylo51!RM;u`!TfWDry`b_s1{V876IHvuTX v;2`MmuK~n>gOC52;A{|sQSY|iZ3c%bHAW!d0`g56UNAEVB3X%|9Fqe8%qkSI literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/009-send.pcap b/autotest/units/001_one_port/050_firewall_state_resend/009-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a324304509bdd12aef4a69458a409cefefafe614 GIT binary patch literal 24 Ycmca|c+)~A1{MYw`2U}Qff2|708wKE@Bjb+ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/010-expect.pcap b/autotest/units/001_one_port/050_firewall_state_resend/010-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a324304509bdd12aef4a69458a409cefefafe614 GIT binary patch literal 24 Ycmca|c+)~A1{MYw`2U}Qff2|708wKE@Bjb+ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/010-send.pcap b/autotest/units/001_one_port/050_firewall_state_resend/010-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..6d229a9d85044cab4838db3a7cb01afa638da1c5 GIT binary patch literal 162 zcmca|c+)~A1{MYw`2U}Qff2}Y+G?KqQj&q83djawV`Crzk}x(lZe(D;&~`Tg$YF30 vwEx!tV!*+t|4eW;h{33LTkkf5L&-ZvMn*0!1_mx6CINK@K_n|tlw)!L>bw-o literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/011-expect.pcap b/autotest/units/001_one_port/050_firewall_state_resend/011-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..1da63435c0bd1e435dfb76efda5275a593367039 GIT binary patch literal 86 zcmca|c+)~A1{MYw`2U}Qff2}Y+G?IEuFSxo2V{dV5GW}rF$gLdyM#6}Fr46EaAjbS b0V%Z?%-_Sv$jHUTz`(^Mq%Od~acVgLj71HR literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/011-send.pcap b/autotest/units/001_one_port/050_firewall_state_resend/011-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..c46cf956723569bd6b5975a1cfe4b0a75be3ba1c GIT binary patch literal 86 zcmca|c+)~A1{MYw`2U}Qff2}Y+G?I!r@+9V2V{dVgP@YJODKpI6l`Q*Na0{`Wnhp2 aDRmIc+r!An$i>CLz{Mn_F2KNXYB>OtKn-31 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/012-expect.pcap b/autotest/units/001_one_port/050_firewall_state_resend/012-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a4cd4731df096820e39157cf73f0f17571e50636 GIT binary patch literal 162 zcmca|c+)~A1{MYw`2U}Qff2}Y+G?KqRh5CE3djawV`Ct}$RMa>>=N3@z<#0aZURt% y!9mdBUjv8%2Os}4!Py`Nquy=3+YAmR?->~xxwse@xP+Jl)ENYktVB_c$pHW)jTK4& literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/012-send.pcap b/autotest/units/001_one_port/050_firewall_state_resend/012-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a324304509bdd12aef4a69458a409cefefafe614 GIT binary patch literal 24 Ycmca|c+)~A1{MYw`2U}Qff2|708wKE@Bjb+ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/autotest.yaml b/autotest/units/001_one_port/050_firewall_state_resend/autotest.yaml new file mode 100644 index 00000000..d7eafc9a --- /dev/null +++ b/autotest/units/001_one_port/050_firewall_state_resend/autotest.yaml @@ -0,0 +1,61 @@ +steps: +- ipv4Update: "0.0.0.0/0 -> 200.0.0.1" +- ipv6Update: "::/0 -> fe80::1" +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap +- sleep: 10 +- sendPackets: + - port: kni0 + send: 003-send.pcap + expect: 003-expect.pcap +- clearFWState: 1 +- sendPackets: + - port: kni0 + send: 004-send.pcap + expect: 004-expect.pcap +- sleep: 1 +- sendPackets: + - port: kni0 + send: 005-send.pcap + expect: 005-expect.pcap +- sleep: 9 +- sendPackets: + - port: kni0 + send: 006-send.pcap + expect: 006-expect.pcap +- clearFWState: 1 +- sendPackets: + - port: kni0 + send: 007-send.pcap + expect: 007-expect.pcap +- sendPackets: + - port: kni0 + send: 008-send.pcap + expect: 008-expect.pcap +- sleep: 10 +- sendPackets: + - port: kni0 + send: 009-send.pcap + expect: 009-expect.pcap +- clearFWState: 1 +- sendPackets: + - port: kni0 + send: 010-send.pcap + expect: 010-expect.pcap +- sleep: 1 +- sendPackets: + - port: kni0 + send: 011-send.pcap + expect: 011-expect.pcap +- sleep: 9 +- sendPackets: + - port: kni0 + send: 012-send.pcap + expect: 012-expect.pcap +- clearFWState: 1 diff --git a/autotest/units/001_one_port/050_firewall_state_resend/controlplane.conf b/autotest/units/001_one_port/050_firewall_state_resend/controlplane.conf new file mode 100644 index 00000000..668bb151 --- /dev/null +++ b/autotest/units/001_one_port/050_firewall_state_resend/controlplane.conf @@ -0,0 +1,64 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.2000": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "2000", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall.txt", + "synchronization": { + "ipv6SourceAddress": "fe80::f1", + "multicastIpv6Address": "ff02::1", + "multicastDestinationPort": 11995, + "logicalPorts": [ + "lp0.2000" + ], + "ingressNextModule": "vrf0" + }, + "nextModules": [ + "vrf0" + ] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv6Prefix": "fe80::2/64", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + }, + "kni0.2000": { + "ipAddresses": ["ff02::2000"], + "neighborIPv6Address": "fe80::2000", + "neighborMacAddress": "00:00:00:33:33:33", + "nextModule": "lp0.2000" + } + } + } + } +} diff --git a/autotest/units/001_one_port/050_firewall_state_resend/firewall.txt b/autotest/units/001_one_port/050_firewall_state_resend/firewall.txt new file mode 100644 index 00000000..9554503a --- /dev/null +++ b/autotest/units/001_one_port/050_firewall_state_resend/firewall.txt @@ -0,0 +1,7 @@ +:BEGIN +add skipto :IN ip from any to any in + +:IN +add allow udp from 10.0.0.0/24 to any 53 keep-state +add allow udp from any to 2020:ddd:ff1c:2030::/60 53 keep-state +add deny ip from any to any diff --git a/autotest/units/001_one_port/050_firewall_state_resend/gen.py b/autotest/units/001_one_port/050_firewall_state_resend/gen.py new file mode 100755 index 00000000..8ea5866b --- /dev/null +++ b/autotest/units/001_one_port/050_firewall_state_resend/gen.py @@ -0,0 +1,200 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import ipaddress +import socket +import struct +from typing import List + +from scapy.layers.inet import UDP, IP +from scapy.layers.inet6 import IPv6 +from scapy.layers.l2 import Ether, Dot1Q +from scapy.packet import Packet, Raw +from scapy.utils import PcapWriter + + +def write_pcap(path: str, packets: List[Packet]) -> None: + with PcapWriter(path) as fh: + for p in packets: + fh.write(p) + + +def ipv4_send(src: str, dst: str) -> Packet: + return Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11") / Dot1Q(vlan=100) / IP(src=src, dst=dst, ttl=64) + + +def ipv4_recv(src: str, dst: str) -> Packet: + return Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55") / Dot1Q(vlan=200) / IP(src=src, dst=dst, ttl=63) + + +def ipv6_send(src: str, dst: str) -> Packet: + return Ether(dst="00:11:22:33:44:55", src="00:00:00:22:22:22") / \ + Dot1Q(vlan=200) / \ + IPv6(src=src, dst=dst, hlim=64, fl=0) + + +def ipv6_recv(src: str, dst: str) -> Packet: + return Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55") / \ + Dot1Q(vlan=100) / \ + IPv6(src=src, dst=dst, hlim=63, fl=0) + + +def make_payload6(src_ip: str, dst_ip: str, src_port: int, dst_port: int) -> bytes: + data = struct.pack( + " bytes: + data = b'' + data += ipaddress.ip_address(dst_ip).packed + data += ipaddress.ip_address(src_ip).packed + + data += struct.pack( + "8IO#q3B zu-OX=Dk*`OP{639zy<0x+~CK2~!X9C$}8JB|vd( h{&Wzu2fGobjlsnQ#n(Vhp|3++<`GNJ$g literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/001-send.pcap b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..f2417c44318399e59c2525dec4115f482798e98f GIT binary patch literal 118 zcmca|c+)~A1{MYw`2U}Qff2~D*lM2ICC1L+2V{dVgP@YJODK?5Qc`MUU^vlsHvuFn n!sZ|-sH6m9LIIiyz;L4NZURVD ogv~)of%ooz83h9n7YGCd1(lQ_ObGvqp$42Az@)$+D8j%103_xS+5i9m literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/004-expect.pcap b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/004-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..96a84f39ab5c730b1f9a5a901ef9c89275e51c63 GIT binary patch literal 374 zcmca|c+)~A1{MYw`2U}Qff2~D*lM1-%!Hl63djawAW%|LVh~g^b_s1{U^v0S;L5?I6f-acFexzj?uVGP*OZ;13Mc`>#>PN`5oQwmg|@p1Kmi5^ zL5F`0AO;+K{LchugBXl@xAkr_I23_x0@-M3@Pe6vjS1m+6y=y4ke^b`5iS9$5EK-I lxr8AF?h<>j8{r1HxBz{Q1Ox>`Ux&VCa425`atb*v0RYIhEwumu literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/004-send.pcap b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/004-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..68b169dba24f00a8791e969232f951acb65ef705 GIT binary patch literal 98 zcmca|c+)~A1{MYw`2U}Qff2~D*lM1-*N~mT3djaw20rrkix;>%D|uj eQtH5#bCw6F2?Us57+8W7gFpb20)y{<1_l6CT@KLz literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/005-expect.pcap b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/005-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a324304509bdd12aef4a69458a409cefefafe614 GIT binary patch literal 24 Ycmca|c+)~A1{MYw`2U}Qff2|708wKE@Bjb+ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/005-send.pcap b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/005-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..42352bf925c35b48671f6c5cdd744952b170c3a3 GIT binary patch literal 162 zcmca|c+)~A1{MYw`2U}Qff2~D*lM1-z?Pk%3djawV`Crzk}x(lZe(D;&~`Tg$YF30 wwEx!tV!*+t|4eW;h{33LTkkf5L!de%BO@0N0|S@g6#;byHYS9XD9SN80L*q2qW}N^ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/006-expect.pcap b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/006-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..63f8e9b9e4ddd14d2eddcf25ee68c917ebbde199 GIT binary patch literal 98 zcmca|c+)~A1{MYw`2U}Qff2~D*lM2o*qNQd3djawAW%|LVh~g^b_s1{U^v0S;L5F#|&YlLA9q4+8@LdVUX% literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/006-send.pcap b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/006-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..aacffa3198d3bacb27068b0b15256c9f11f8f6ea GIT binary patch literal 98 zcmca|c+)~A1{MYw`2U}Qff2~D*lM2Y;>gZm1!RLTgP@YJODKpI6l`Q*Na0{`Wnj<% hDRp4W+0Dqv$i>6Jz;(q?T>zvQ1Ok{87}|Om7yvi64psmF literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/007-expect-tcp.pcap b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/007-expect-tcp.pcap new file mode 100644 index 0000000000000000000000000000000000000000..7e5256ee2f15be87194d5b54977c7b72069aeedf GIT binary patch literal 588 zcmca|c+)~A1{MYw`2U}Qff2~D*lM2I7{Siq2V{dV5C{qiG6*UeyM#6}Fr>8IO#q3B zu-OX=Dk*`OP{639z=90Zn_ZA zbU}#e1yRJ9j&2&dZ76OR0GcigF+D1p7}L>BL$?jZ?TkRvf#C=WcZV2aOh-2j-8K}r Z3j$3Sf|#xnON{C0rlH%0;&y1r001Y4OuhgB literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/007-expect-tech.pcap b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/007-expect-tech.pcap new file mode 100644 index 0000000000000000000000000000000000000000..d534073aa830eeb4ae976e89fa67910dd6db2866 GIT binary patch literal 300 zcmca|c+)~A1{MYw`2U}Qff2~D*lM22*vigO1!RM;u`!TfWDry`b_s1{V876IHvuTX z;2`MmuK~n>gOC52;A{|sQSY|iZ3c%s%`j0*15RcJHYPSD1>U>=WfTmc;*5fVN=h&_ zAbl`4$R*R;5H10V3knLtT*8n7cZogNjWBHtE-onM0X2ob4t>qw@JJ7)gjAOR0Fiyz;L4NZURVD zgv~)vP)P~IgaSq-1>U>=WfTlxd}dAqOPFK;lLEsnMTqG;-H9sw++SZ0zlJ+A*N68B*t`f)6i{0aXTZ>bYM7w!oAvy7}L>BL$?jZ Z?Seqlg&?M 200.0.0.1" +- ipv6Update: "::/0 -> fe80::1" +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap +- sleep: 1 +- sendPackets: + - port: kni0 + send: 003-send.pcap + expect: 003-expect.pcap +- clearFWState: 1 +- sendPackets: + - port: kni0 + send: 004-send.pcap + expect: 004-expect.pcap +- sendPackets: + - port: kni0 + send: 005-send.pcap + expect: 005-expect.pcap +- sleep: 1 +- sendPackets: + - port: kni0 + send: 006-send.pcap + expect: 006-expect.pcap +- sendPackets: + - port: kni0 + send: 007-send.pcap + expect: + - 007-expect-tcp.pcap + - 007-expect-tech.pcap +- cli: "fw list states | grep 'allow tcp from 2220:ddd:ff1c:2030::1 12345 to 1111:2222::1 777' | grep 'flags SAF:SAF'" +- clearFWState: 1 diff --git a/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/controlplane.conf b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/controlplane.conf new file mode 100644 index 00000000..9ef9dfcd --- /dev/null +++ b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/controlplane.conf @@ -0,0 +1,67 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.2000": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "2000", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall.txt", + "synchronization": { + "ipv6SourceAddress": "fe80::f1", + "multicastIpv6Address": "ff02::1", + "unicastIpv6SourceAddress": "3333::4444", + "unicastIpv6Address": "2222::1111", + "multicastDestinationPort": 11995, + "unicastDestinationPort": 21995, + "logicalPorts": [ + "lp0.2000" + ], + "ingressNextModule": "vrf0" + }, + "nextModules": [ + "vrf0" + ] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv6Prefix": "fe80::2/64", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + }, + "kni0.2000": { + "ipAddresses": ["ff02::2000"], + "neighborIPv6Address": "fe80::2000", + "neighborMacAddress": "00:00:00:33:33:33", + "nextModule": "lp0.2000" + } + } + } + } +} diff --git a/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/firewall.txt b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/firewall.txt new file mode 100644 index 00000000..539109ae --- /dev/null +++ b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/firewall.txt @@ -0,0 +1,7 @@ +:BEGIN +add skipto :IN ip from any to any in + +:IN +add allow tcp from 12.0.0.0/24 to any 12345 keep-state +add allow tcp from any to 2220:ddd:ff1c:2030::/60 12345 keep-state +add deny ip from any to any diff --git a/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/gen.py b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/gen.py new file mode 100755 index 00000000..1cea9e98 --- /dev/null +++ b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/gen.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import ipaddress +import socket +import struct +from typing import List + +from scapy.layers.inet import UDP, IP, TCP +from scapy.layers.inet6 import IPv6 +from scapy.layers.l2 import Ether, Dot1Q +from scapy.packet import Packet, Raw +from scapy.utils import PcapWriter + + +def write_pcap(path: str, packets: List[Packet]) -> None: + with PcapWriter(path) as fh: + for p in packets: + fh.write(p) + + +def ipv4_send(src: str, dst: str) -> Packet: + return Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11") / Dot1Q(vlan=100) / IP(src=src, dst=dst, ttl=64) + + +def ipv4_recv(src: str, dst: str) -> Packet: + return Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55") / Dot1Q(vlan=200) / IP(src=src, dst=dst, ttl=63) + + +def ipv6_send(src: str, dst: str) -> Packet: + return Ether(dst="00:11:22:33:44:55", src="00:00:00:22:22:22") / \ + Dot1Q(vlan=200) / \ + IPv6(src=src, dst=dst, hlim=64, fl=0) + + +def ipv6_recv(src: str, dst: str) -> Packet: + return Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55") / \ + Dot1Q(vlan=100) / \ + IPv6(src=src, dst=dst, hlim=63, fl=0) + + +def make_payload6(proto: int, src_ip: str, dst_ip: str, src_port: int, dst_port: int, flags: int) -> bytes: + data = struct.pack( + " bytes: + data = b'' + data += ipaddress.ip_address(dst_ip).packed + data += ipaddress.ip_address(src_ip).packed + + data += struct.pack( + " 200.0.0.1" +- ipv6Update: "::/0 -> fe80::1" +- sendPackets: + - port: kni0 + send: decap.pcap + expect: decap_expect.pcap +- sendPackets: + - port: kni0 + send: encap.pcap + expect: encap_expect.pcap +- sendPackets: + - port: kni0 + send: encap_rnd.pcap + expect: encap_rnd_expect.pcap diff --git a/autotest/units/001_one_port/051_tun64/controlplane.conf b/autotest/units/001_one_port/051_tun64/controlplane.conf new file mode 100644 index 00000000..ce0b4fd0 --- /dev/null +++ b/autotest/units/001_one_port/051_tun64/controlplane.conf @@ -0,0 +1,91 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "nextModules": [ + "mgif0", + "mgif1" + ] + }, + "mgif0": { + "type": "tun64", + "ipv6SourceAddress": "2020:ddd:b010:a0ff::1", + "prefixes": [ + "1.23.111.0/24", + "11.220.222.64/28", + "111.222.128.16/28" + ], + "mappings": { + "1.23.111.4": { + "net_loc": "LOC1", + "scheme": "tun64", + "fqdn": "2020:ddd:ccc:4444:111:111:0:2222", + "addr6": "2020:ddd:ccc:4444:111:111:0:2222" + }, + "1.23.111.5": { + "net_loc": "LOC1", + "scheme": "tun64", + "fqdn": "2020:ddd:ccc:6666:111:3333:0:7777", + "addr6": "2020:ddd:ccc:6666:111:3333:0:7777" + }, + "11.220.222.73": { + "net_loc": "LOC2", + "scheme": "tun64", + "fqdn": "2020:ddd:ccc:5555:0:4567:5555:9999", + "addr6": "2020:ddd:ccc:5555:0:4567:5555:9999" + }, + "111.222.128.16": { + "net_loc": "LOC2", + "scheme": "tun64", + "fqdn": "fqdn1.net", + "addr6": "2020:ddd:ccc:7777:0:777:aaaa:5555" + } + }, + "nextModule": "vrf0" + }, + "mgif1": { + "type": "tun64", + "ipv6SourceAddress": "2020:ddd:abcd::", + "random_source": "true", + "prefixes": [ + "1.23.123.128/25", + "123.0.250.64/26" + ], + "mappings": [ + "map64_rndsrc.json" + ], + "nextModule": "vrf0" + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv6Prefix": "fe80::2/64", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/051_tun64/decap.pcap b/autotest/units/001_one_port/051_tun64/decap.pcap new file mode 100644 index 0000000000000000000000000000000000000000..1c1d35afac2be4a7c0eb9f3ac10bdd21040d506f GIT binary patch literal 228 zcmca|c+)~A1{MYw`2U}Qff2?5(qT}{AgE;Q5(<`JY-C_aX}g;M;>fT#C@ApWaO3sz63MF#g)gD4x&40Rjx)Ve()_SZrZJwdG#}#5f3f Q>K|@f5-xB7y?|^B07@JroB#j- literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/051_tun64/decap_expect.pcap b/autotest/units/001_one_port/051_tun64/decap_expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..007e09df5a78862c0e17650755c8fcf016dafc91 GIT binary patch literal 148 zcmca|c+)~A1{MYw`2U}Qff2?5(t1z~q?DAD7zCA!T|yff7*237xH2%vfRx%Z{@%(c Zp3lMo0u0}Q`VoK_-H8{tfL0>w1_1u?6bk?V literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/051_tun64/encap.pcap b/autotest/units/001_one_port/051_tun64/encap.pcap new file mode 100644 index 0000000000000000000000000000000000000000..29acbb1ed78812323782b4750bf08900aae86e05 GIT binary patch literal 148 zcmca|c+)~A1{MYw`2U}Qff2?5(t1$LAgE;Q5(?xfDJeBFFr46EaAjbS0V%a+{J)h0 f2pGllSvVNJ1N9>SVcial4Vyu_x$oR_gy{wV8I2YR literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/051_tun64/encap_expect.pcap b/autotest/units/001_one_port/051_tun64/encap_expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..8e1b2c05c04cecc0170d46bb05960f8ca3a5e991 GIT binary patch literal 126 zcmca|c+)~A1{MYw`2U}Qff2?5(qT{xqyz;883dJ#T|yff7*g8qCIE#PWLWGK6nO7$ u5Lf`z2L_BFKF=8!7e+xwK?VjTC0C#-kdfAm|F?1g0i$?63kSn@uzCP01{F*I literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/051_tun64/encap_rnd.pcap b/autotest/units/001_one_port/051_tun64/encap_rnd.pcap new file mode 100644 index 0000000000000000000000000000000000000000..18fccacb0ff7ee12e0a6169769afb1f2f8ada41a GIT binary patch literal 148 zcmca|c+)~A1{MYw`2U}Qff2?5(t1$LAgE;Q5(?xfDJeBFFr46EaAjbS0V%a+{A|nt d1dQUs-`odnO*=fJyMt$x1+li-7gHL Uh>$^cJJn1F1vMCeO$WLi0GWU?yZ`_I literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/052_firewall_samples/001-send.pcap b/autotest/units/001_one_port/052_firewall_samples/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a9c453a3b593500de7417049211e0b2a82a1713c GIT binary patch literal 588 zcmca|c+)~A1{MYw`2U}Qff300xz#+ik%gbZ56A{#20iyz;L4NZURVD zgv~)vP)P~IgaSrIL9SK*WfTlxe4yE;Fv$QW1qR+is+!J-W_kg{^k_C>+>Y*6biXi| zB0>h)?Nl=z6x3h=N3@z;J?t!IgnQ z1EkcRE$=KhP!k9M%`t^2W?%?lQedcCO}0slXeO 200.0.0.1" +- ipv6Update: "::/0 -> fe80::1" +- sleep: 1 +- cli: "samples show" +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap +- cli: "samples dump | diff - TESTDIR/samples.json" +- clearFWState: 1 diff --git a/autotest/units/001_one_port/052_firewall_samples/controlplane.conf b/autotest/units/001_one_port/052_firewall_samples/controlplane.conf new file mode 100644 index 00000000..0b1f589e --- /dev/null +++ b/autotest/units/001_one_port/052_firewall_samples/controlplane.conf @@ -0,0 +1,43 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall.txt", + "nextModules": [ + "vrf0" + ], + "storeSamples": true + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv6Prefix": "fe80::2/64", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/052_firewall_samples/firewall.txt b/autotest/units/001_one_port/052_firewall_samples/firewall.txt new file mode 100644 index 00000000..d9986a09 --- /dev/null +++ b/autotest/units/001_one_port/052_firewall_samples/firewall.txt @@ -0,0 +1,7 @@ +:BEGIN +add skipto :IN ip from any to any in + +:IN +add allow tcp from 11.0.0.0/24 to any 53 keep-state +add allow tcp from any to 2111:aaa:ff1c:2030::/60 53 keep-state +add deny ip from any to any diff --git a/autotest/units/001_one_port/052_firewall_samples/gen.py b/autotest/units/001_one_port/052_firewall_samples/gen.py new file mode 100755 index 00000000..f324f12b --- /dev/null +++ b/autotest/units/001_one_port/052_firewall_samples/gen.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +from typing import List + +from scapy.layers.inet import TCP, IP +from scapy.layers.inet6 import IPv6 +from scapy.layers.l2 import Ether, Dot1Q +from scapy.packet import Packet +from scapy.utils import PcapWriter + + +def write_pcap(path: str, packets: List[Packet]) -> None: + with PcapWriter(path) as fh: + for p in packets: + fh.write(p) + + +def ipv4_send(src: str, dst: str) -> Packet: + return Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11") / Dot1Q(vlan=100) / IP(src=src, dst=dst, ttl=64) + + +def ipv4_recv(src: str, dst: str) -> Packet: + return Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55") / Dot1Q(vlan=200) / IP(src=src, dst=dst, ttl=63) + + +def ipv6_send(src: str, dst: str) -> Packet: + return Ether(dst="00:11:22:33:44:55", src="00:00:00:22:22:22") / \ + Dot1Q(vlan=200) / \ + IPv6(src=src, dst=dst, hlim=64, fl=0) + + +def ipv6_recv(src: str, dst: str) -> Packet: + return Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55") / \ + Dot1Q(vlan=100) / \ + IPv6(src=src, dst=dst, hlim=63, fl=0) + + +write_pcap("001-send.pcap", [ + # Direct ... + ipv6_send("1111:2222::1", "2111:aaa:ff1c:2030::1") / TCP(sport=(1024, 1025), dport=53), + # ... and reverse. + ipv6_send("2111:aaa:ff1c:2030::1", "1111:2222::1") / TCP(sport=53, dport=(1024, 1025)), + # Drop: different dst port. + ipv6_send("1111:2222::1", "2111:aaa:ff1c:2030::1") / TCP(sport=10000, dport=54), + # Drop: different dst addr. + ipv6_send("1111:2222::1", "2111:aaa:ff1c:2040::ff") / TCP(sport=10000, dport=53), +]) + +write_pcap("001-expect.pcap", [ + ipv6_recv("1111:2222::1", "2111:aaa:ff1c:2030::1") / TCP(sport=(1024, 1025), dport=53), + ipv6_recv("2111:aaa:ff1c:2030::1", "1111:2222::1") / TCP(sport=53, dport=(1024, 1025)), +]) + +write_pcap("002-send.pcap", [ + # Direct ... + ipv4_send("11.0.0.1", "1.1.1.1") / TCP(sport=(1024, 1025), dport=53), + # ... and reverse. + ipv4_send("1.1.1.1", "11.0.0.1") / TCP(sport=53, dport=(1024, 1025)), + # Drop: different dst port. + ipv4_send("11.0.0.1", "1.1.1.1") / TCP(sport=10000, dport=54), + # Drop: different src addr. + ipv4_send("11.0.1.1", "1.1.1.1") / TCP(sport=10000, dport=53), +]) + +write_pcap("002-expect.pcap", [ + ipv4_recv("11.0.0.1", "1.1.1.1") / TCP(sport=(1024, 1025), dport=53), + ipv4_recv("1.1.1.1", "11.0.0.1") / TCP(sport=53, dport=(1024, 1025)), +]) diff --git a/autotest/units/001_one_port/052_firewall_samples/samples.json b/autotest/units/001_one_port/052_firewall_samples/samples.json new file mode 100644 index 00000000..397cf2d9 --- /dev/null +++ b/autotest/units/001_one_port/052_firewall_samples/samples.json @@ -0,0 +1,7 @@ +[ +{"in_iface":"lp0.100","out_iface":"lp0.200","proto":6,"src_addr":"1.1.1.1","src_port":53,"dst_addr":"11.0.0.1","dst_port":1024}, +{"in_iface":"lp0.100","out_iface":"lp0.200","proto":6,"src_addr":"11.0.0.1","src_port":1024,"dst_addr":"1.1.1.1","dst_port":53}, +{"in_iface":"lp0.100","out_iface":"lp0.200","proto":6,"src_addr":"11.0.0.1","src_port":1025,"dst_addr":"1.1.1.1","dst_port":53}, +{"in_iface":"lp0.200","out_iface":"lp0.100","proto":6,"src_addr":"2111:aaa:ff1c:2030::1","src_port":53,"dst_addr":"1111:2222::1","dst_port":1024}, +{"in_iface":"lp0.200","out_iface":"lp0.100","proto":6,"src_addr":"1111:2222::1","src_port":1024,"dst_addr":"2111:aaa:ff1c:2030::1","dst_port":53}, +{"in_iface":"lp0.200","out_iface":"lp0.100","proto":6,"src_addr":"1111:2222::1","src_port":1025,"dst_addr":"2111:aaa:ff1c:2030::1","dst_port":53}] diff --git a/autotest/units/001_one_port/053_firewall_defaults/001-expect.pcap b/autotest/units/001_one_port/053_firewall_defaults/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..f43bf27d050ff3e66ad985b6730e8ff8af308dac GIT binary patch literal 282 zcmca|c+)~A1{MYw`2U}Qff2~zKWLu1aupkc6OawUKp-e6$RMa>>=N3@z>v~*HvuHZ zA!sissH6m9LIIiyz;L4NZURV@ zL(oA`P)P~IgaSqd1>U>=WfTlxe02c^QwEL*DUgX<7E{ASpli(-II1;4CeB#G#^49E i3WRaEQG^ZMjm8QJf`UkHGzOapb#MTa0t5Rr1_l7W94KM{ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/053_firewall_defaults/autotest.yaml b/autotest/units/001_one_port/053_firewall_defaults/autotest.yaml new file mode 100644 index 00000000..10647965 --- /dev/null +++ b/autotest/units/001_one_port/053_firewall_defaults/autotest.yaml @@ -0,0 +1,7 @@ +steps: +- ipv4Update: "0.0.0.0/0 -> 200.0.0.1" +- ipv6Update: "::/0 -> fe80::1" +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap diff --git a/autotest/units/001_one_port/053_firewall_defaults/controlplane.conf b/autotest/units/001_one_port/053_firewall_defaults/controlplane.conf new file mode 100644 index 00000000..3c0da4fd --- /dev/null +++ b/autotest/units/001_one_port/053_firewall_defaults/controlplane.conf @@ -0,0 +1,42 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall.txt", + "nextModules": [ + "vrf0" + ] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv6Prefix": "fe80::2/64", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/053_firewall_defaults/firewall.txt b/autotest/units/001_one_port/053_firewall_defaults/firewall.txt new file mode 100644 index 00000000..fd422545 --- /dev/null +++ b/autotest/units/001_one_port/053_firewall_defaults/firewall.txt @@ -0,0 +1,2 @@ +:BEGIN +add allow udp from any to 2020:ddd:ff1c:2030::/60 53 diff --git a/autotest/units/001_one_port/053_firewall_defaults/gen.py b/autotest/units/001_one_port/053_firewall_defaults/gen.py new file mode 100755 index 00000000..3f105d80 --- /dev/null +++ b/autotest/units/001_one_port/053_firewall_defaults/gen.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +from typing import List + +from scapy.layers.inet import UDP, IP, TCP +from scapy.layers.inet6 import IPv6 +from scapy.layers.l2 import Ether, Dot1Q +from scapy.packet import Packet +from scapy.utils import PcapWriter + + +def write_pcap(path: str, packets: List[Packet]) -> None: + with PcapWriter(path) as fh: + for p in packets: + fh.write(p) + + +def ipv6_send(src: str, dst: str) -> Packet: + return Ether(dst="00:11:22:33:44:55", src="00:00:00:22:22:22") / \ + Dot1Q(vlan=200) / \ + IPv6(src=src, dst=dst, hlim=64, fl=0) + + +def ipv6_recv(src: str, dst: str) -> Packet: + return Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55") / \ + Dot1Q(vlan=100) / \ + IPv6(src=src, dst=dst, hlim=63, fl=0) + + +write_pcap("001-send.pcap", [ + # Allow. + ipv6_send("1111:2222::1", "2020:ddd:ff1c:2030::1") / UDP(sport=10000, dport=53), + + ipv6_send("1111:2222::1", "2020:ddd:ff1c:2030::1") / UDP(sport=(1024), dport=54), + + ipv6_send("1111:2222::33", "2020:1111:ff1c:2030::33") / TCP(sport=(1024), dport=54), +]) + +write_pcap("001-expect.pcap", [ + ipv6_recv("1111:2222::1", "2020:ddd:ff1c:2030::1") / UDP(sport=10000, dport=53), + ipv6_recv("1111:2222::1", "2020:ddd:ff1c:2030::1") / UDP(sport=1024, dport=54), + ipv6_recv("1111:2222::33", "2020:1111:ff1c:2030::33") / TCP(sport=(1024), dport=54), + +]) diff --git a/autotest/units/001_one_port/054_gapped_masks_112/001-expect.pcap b/autotest/units/001_one_port/054_gapped_masks_112/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..164af9508dc3df1d99a8deb5b14711e1200667a8 GIT binary patch literal 118 zcmca|c+)~A1{MYw`2U}Qff2?5(tc13qyz;883dJ#T|yff7*g8qCIE#PMA+;V6nO9Q q@Ch(8FtC;W|H8ls;xjOq03}F7#IL$1QMJ8 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/054_gapped_masks_112/001-send.pcap b/autotest/units/001_one_port/054_gapped_masks_112/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..7df4bdb63d6c395041bfcff3562e1f5f9183647b GIT binary patch literal 118 zcmca|c+)~A1{MYw`2U}Qff2?5(tc3PAgE;Q5(?xfDJeBFFq~++n*ii6h_E>*DDd9p r;S*qHU|=i#|Am1O#AjeI0ZO)70SV^A0So~^8VmxM6d0!TF)#oCkSP;1 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/054_gapped_masks_112/autotest.yaml b/autotest/units/001_one_port/054_gapped_masks_112/autotest.yaml new file mode 100644 index 00000000..10647965 --- /dev/null +++ b/autotest/units/001_one_port/054_gapped_masks_112/autotest.yaml @@ -0,0 +1,7 @@ +steps: +- ipv4Update: "0.0.0.0/0 -> 200.0.0.1" +- ipv6Update: "::/0 -> fe80::1" +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap diff --git a/autotest/units/001_one_port/054_gapped_masks_112/controlplane.conf b/autotest/units/001_one_port/054_gapped_masks_112/controlplane.conf new file mode 100644 index 00000000..957964d2 --- /dev/null +++ b/autotest/units/001_one_port/054_gapped_masks_112/controlplane.conf @@ -0,0 +1,46 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall.txt", + "nextModules": [ + "vrf0" + ] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipAddresses": [ + "fe80::2" + ], + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipAddresses": [ + "200.0.0.2" + ], + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/054_gapped_masks_112/firewall.txt b/autotest/units/001_one_port/054_gapped_masks_112/firewall.txt new file mode 100644 index 00000000..c3757db2 --- /dev/null +++ b/autotest/units/001_one_port/054_gapped_masks_112/firewall.txt @@ -0,0 +1,7 @@ +:BEGIN +add skipto :IN ip from any to any in + +:IN +add allow tcp from 2020:ddd:c0e:1003:0:675:fff4::/112 to 2020:ddd:0:3400:0:853a:0:3 80 +add allow tcp from 2020:ddd:c00:0:0:675::/ffff:ffff:ff00:0000:ffff:ffff:: to 2020:ddd:0:3400:0:1234:: 80 +add deny ip from any to any diff --git a/autotest/units/001_one_port/054_gapped_masks_112/gen.py b/autotest/units/001_one_port/054_gapped_masks_112/gen.py new file mode 100755 index 00000000..05cc23d0 --- /dev/null +++ b/autotest/units/001_one_port/054_gapped_masks_112/gen.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * + + +def write_pcap(filename, *packetsList): + if len(packetsList) == 0: + PcapWriter(filename)._write_header(Ether()) + return + + PcapWriter(filename) + + for packets in packetsList: + if type(packets) == list: + for packet in packets: + packet.time = 0 + wrpcap(filename, [p for p in packet], append=True) + else: + packets.time = 0 + wrpcap(filename, [p for p in packets], append=True) + + +def ipv6_send(_src, _dst): + return Ether(dst="00:11:22:33:44:55", src="00:00:00:22:22:22")/Dot1Q(vlan=200)/IPv6(src=_src, dst=_dst, hlim=64, fl=0) + + +def ipv6_recv(_src, _dst): + return Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(src=_src, dst=_dst, hlim=63, fl=0) + + +write_pcap("001-send.pcap", *[ + ipv6_send("2020:ddd:c0e:1003:0:675:fff4:1", "2020:ddd:0:3400:0:853a:0:3")/TCP(sport=50000, dport=80, flags="S") +]) + + +write_pcap("001-expect.pcap", *[ + ipv6_recv("2020:ddd:c0e:1003:0:675:fff4:1", "2020:ddd:0:3400:0:853a:0:3")/TCP(sport=50000, dport=80, flags="S") +]) diff --git a/autotest/units/001_one_port/055_balancer_wlc/001-expect.pcap b/autotest/units/001_one_port/055_balancer_wlc/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..85cd0cb89836322bbab65d5da81fea2c162d6759 GIT binary patch literal 3672 zcmcJRF;2rk5Jh+FKtV@M6CnypBnnC*0ex&pj}Wze1{zL45+rE20xcz1pye+7apLSS z9($D$tdz)3Hu>6l^XL2P^ZhLgqp(?%5NLA~!X2*p)hr78ho_gbhY;=`zi;`Y>Tjr`d4&x!FQXLU11l0IoYkBdCwk&vy&J4Xm?DraVTf)-Ij{{hgvZgic4%DQ}M>B zm>G&B6cJz_wE{;nITk*S4aQDYg<`$rx|^Njt17oem!qg^y?~<0vGi4yg2hpE zPCbXB$+7fS)#4}>pP*=REDJW)YVl0vSF?uaDnsg4RVY^A*yBeh$3}9 nSq{N4Jah2$h-Gz-_gT*Lqv%zUkNS*Gj;0?)uZn!sis1MIq%%i3 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/055_balancer_wlc/001-send.pcap b/autotest/units/001_one_port/055_balancer_wlc/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..16492d1a61be130cb96d213d0b116facd47d4e4c GIT binary patch literal 2392 zcmbW1J#NB45JqQA6h(C0AWD@oQi@2aD4=II$u-tz$Q{Cu6dJBTOG(24xDR|dS?y{x zmiVv)mcf4VJdNIQzuh!)C;2#?L^NOE{Qm!u(bMbXtNWw*7CAh~ROI<`>-fH1U7i@K zyuJMDuDb_cv*uCa-xJ+WSCN(=sZ09I+$-N{0aD|VK1k9Wq=8F{94Wz*x}E~*DZ!Jv zo&xD9!IQe40_iEile(S)>8V{Rl)J{s>DmQIuBS*&*Umw5JwU!sy8a|IA<#7MiS&dm P$bGUT(o@wZOM<5}Cw1{4 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/055_balancer_wlc/002-expect.pcap b/autotest/units/001_one_port/055_balancer_wlc/002-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..61fbaec326e61a3c45e17ccfd9ca80e60fbc4cbe GIT binary patch literal 3672 zcmcJRJx;?w5QTS~KtV@M6Cnx;ItuD6)#Z?H>$Io|AEbkCNAql0((T#-(1O2K0bkK%f)Nsr=r ztYSJ^cof%T&3WuK=BC=sbnfn*!%bChi>$|P3Zm<=;if8~;IW&4=z46}sd^sMQ|=i= z*JE>{!TMWzrs}I-`EykzWv7aCV2|gKOox75o(PXC@<@6t<`EuO=-E{|}S_lOe!d-^-a5;>3Pz5+4!qa|`4(R~GC>_n+a literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/055_balancer_wlc/002-send.pcap b/autotest/units/001_one_port/055_balancer_wlc/002-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..45e26a17575792187cb68165ef942f363a4c1947 GIT binary patch literal 2392 zcmbW2F>b;@5JhL4C_;3(L6j;*x)cNm5(V@$>tn3XkUPYXmMZ`qB~1>%eaJWR%B#^J z`D4kpR$f18p1!}&r`@)YM@h%!BBE)5`=mYP`SoKFt`CZDk-vc~Mc$gN^QY>!d1I(D zdf)5ux(An4@gn6ct$LC+AgN3GB1vnI3YRn`Ni|3hE~$~z9(_DTcv9C>AU#ERQrA-; zJw=_%`{gXt$WPhCG*66p!aO#Ng@q$eaZ^^+x$p0a*2 zBsx!BKUos#DeEUoB0XjOWJ#o_te*^tZk4W|EQy>h>nBTMr|bI3l0NV5CqttDE%4O# TlO>U!vVO88(o@z?mIP1#Pj&Gi literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/055_balancer_wlc/003-expect.pcap b/autotest/units/001_one_port/055_balancer_wlc/003-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..553d1483dce0606e34b0b108ab113decc05e7a0a GIT binary patch literal 3672 zcmbW4Jx;?w5QTTVfr5^jCPEYxbQJuHNI;L|(4&abJ_HRXAPFs306I#pK+9d2jc|4t z9$ERV6gfeweC&LFe(?G6@?3>MSguhBviuOjMBk^^VoBKC-oL!L58>|N>o)ypcW^!o zYg_59glciwxk#7g8eHkF^p&Ia_9^YzkZ`c~D(~Hn>uMOrXWgfs#PqAm3gTRe0*R+2 zF&)wq#hh`b#0nBmNMbAyr%H^Fc+3$K@Xr~I$3{Iy=&>d}#)8L2Jx1uUCOt;v(VkH~ zM(D97Jx1iw64hgb9&65{6!SP2-2?9&ZmLotkH6EQdmxdUs#M5hGtm9yyPF`ti;6 zBbP_*KJX;B>B#-)iCiAF`vB2A<=Whjp2&IB?gK=VjyCtBCz2jv9?cm|KRP0rN9{gv zMoY~7=!v99m`5|!CikN!k{*kB%>C$zoX0->=!j!(s(t#=6S=A4el&NErladePh_Wx z@@R>`<_4o}K14m~7 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/055_balancer_wlc/003-send.pcap b/autotest/units/001_one_port/055_balancer_wlc/003-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..986a2356bb9792e5b087180b76066f8498707e7b GIT binary patch literal 2392 zcmbW2OKJi^6h+^w5($}Q2f>j8XBp(9fehkY=*}*x7m+z2GLn294kDUw@cwXq$<^fM`Q`K=yo&r>$Wml_{OHrTdshi^ zsd78p={|pX6|SXy%y$DxTaeTxElAP^q~Ma~Bxwy&bV)}!=WB?k1W(cR)R3MMJVn=2 zLwZW^6kSgZ=_$cebUihsr*5lS*%NuXZUd6*sU=U>twC}L|! TPnJY_D*9weq^F`!mIP0KE~fC{ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/055_balancer_wlc/autotest.yaml b/autotest/units/001_one_port/055_balancer_wlc/autotest.yaml new file mode 100644 index 00000000..15ae3176 --- /dev/null +++ b/autotest/units/001_one_port/055_balancer_wlc/autotest.yaml @@ -0,0 +1,50 @@ +steps: +- ipv4Update: "0.0.0.0/0 -> 200.0.0.1" +- ipv6Update: "::/0 -> fe80::1" +- cli: + - balancer real enable balancer0 10.1.0.55 tcp 443 2443::1 443 + - balancer real enable balancer0 10.1.0.55 tcp 443 2443::2 443 + - balancer real enable balancer0 10.1.0.55 tcp 443 2443::3 443 + - balancer real flush +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- cli_check: | + YANET_FORMAT_COLUMNS=module,virtual_ip,proto,virtual_port,scheduler,real_ip,real_port,enabled,weight,connections,packets,bytes balancer real any + module virtual_ip proto virtual_port scheduler real_ip real_port enabled weight connections packets bytes + --------- ---------- ----- ------------ --------- ------- --------- ------- ------ ----------- ------- ----- + balancer0 10.1.0.55 tcp 443 wlc 2443::1 443 true 2 16 16 1568 + balancer0 10.1.0.55 tcp 443 wlc 2443::2 443 true 1 8 8 784 + balancer0 10.1.0.55 tcp 443 wlc 2443::3 443 true 1 8 8 784 + balancer0 10.1.0.55 tcp 443 wlc 2443::4 443 false 4 0 0 0 + +- cli: + - balancer real enable balancer0 10.1.0.55 tcp 443 2443::4 443 + - balancer real flush +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap +- cli_check: | + YANET_FORMAT_COLUMNS=module,virtual_ip,proto,virtual_port,scheduler,real_ip,real_port,enabled,weight,connections,packets,bytes balancer real any + module virtual_ip proto virtual_port scheduler real_ip real_port enabled weight connections packets bytes + --------- ---------- ----- ------------ --------- ------- --------- ------- ------ ----------- ------- ----- + balancer0 10.1.0.55 tcp 443 wlc 2443::1 443 true 2 17 17 1666 + balancer0 10.1.0.55 tcp 443 wlc 2443::2 443 true 1 10 10 980 + balancer0 10.1.0.55 tcp 443 wlc 2443::3 443 true 1 9 9 882 + balancer0 10.1.0.55 tcp 443 wlc 2443::4 443 true 4 28 28 2744 + +- sleep: 2 +- sendPackets: + - port: kni0 + send: 003-send.pcap + expect: 003-expect.pcap +- cli_check: | + YANET_FORMAT_COLUMNS=module,virtual_ip,proto,virtual_port,scheduler,real_ip,real_port,enabled,weight,connections,packets,bytes balancer real any + module virtual_ip proto virtual_port scheduler real_ip real_port enabled weight connections packets bytes + --------- ---------- ----- ------------ --------- ------- --------- ------- ------ ----------- ------- ----- + balancer0 10.1.0.55 tcp 443 wlc 2443::1 443 true 2 24 24 2352 + balancer0 10.1.0.55 tcp 443 wlc 2443::2 443 true 1 11 11 1078 + balancer0 10.1.0.55 tcp 443 wlc 2443::3 443 true 1 12 12 1176 + balancer0 10.1.0.55 tcp 443 wlc 2443::4 443 true 4 49 49 4802 diff --git a/autotest/units/001_one_port/055_balancer_wlc/controlplane.conf b/autotest/units/001_one_port/055_balancer_wlc/controlplane.conf new file mode 100644 index 00000000..6c5d8a6b --- /dev/null +++ b/autotest/units/001_one_port/055_balancer_wlc/controlplane.conf @@ -0,0 +1,47 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "nextModules": [ + "balancer0", + "route0" + ] + }, + "balancer0": { + "type": "balancer", + "source": "2000:51b::1", + "services": "services.conf", + "default_wlc_power": 10, + "nextModule": "route0" + }, + "route0": { + "type": "route", + "interfaces": { + "kni0.100": { + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:00:00:01", + "nextModule": "lp0.100" + }, + "kni0.200": { + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:00:00:02", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/055_balancer_wlc/gen.py b/autotest/units/001_one_port/055_balancer_wlc/gen.py new file mode 100755 index 00000000..16d642ef --- /dev/null +++ b/autotest/units/001_one_port/055_balancer_wlc/gen.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * + + +def write_pcap(filename, *packetsList): + if len(packetsList) == 0: + PcapWriter(filename)._write_header(Ether()) + return + + PcapWriter(filename) + + for packets in packetsList: + if type(packets) == list: + for packet in packets: + packet.time = 0 + wrpcap(filename, [p for p in packet], append=True) + else: + packets.time = 0 + wrpcap(filename, [p for p in packets], append=True) + + +packages1 = [Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02") / Dot1Q(vlan=200) / IP(dst="10.1.0.55", src=f"1.{a_h}.{a_m}.{a_l}", ttl=64) / TCP(dport=443, sport=sport) + for sport in (12443, 12444) for a_h in range(2) for a_m in range(2) for a_l in range(4)] +packages2 = [Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02") / Dot1Q(vlan=200) / IP(dst="10.1.0.55", src=f"1.{a_h}.{a_m}.{a_l}", ttl=64) / TCP(dport=443, sport=sport) + for sport in (11443, 11444) for a_h in range(2) for a_m in range(0, 2) for a_l in range(4)] +packages3 = [Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02") / Dot1Q(vlan=200) / IP(dst="10.1.0.55", src=f"1.{a_h}.{a_m}.{a_l}", ttl=64) / TCP(dport=443, sport=sport) + for sport in (11443, 11444) for a_h in range(2) for a_m in range(2, 4) for a_l in range(4)] + +write_pcap("001-send.pcap", *packages1) +write_pcap("002-send.pcap", *packages2) +write_pcap("003-send.pcap", *packages3) diff --git a/autotest/units/001_one_port/055_balancer_wlc/services.conf b/autotest/units/001_one_port/055_balancer_wlc/services.conf new file mode 100644 index 00000000..b0821458 --- /dev/null +++ b/autotest/units/001_one_port/055_balancer_wlc/services.conf @@ -0,0 +1,30 @@ +[ + { + "vip": "10.1.0.55", + "proto": "tcp", + "vport": "443", + "scheduler": "wlc", + "reals": [ + { + "ip": "2443::1", + "port": "443", + "weight": "2" + }, + { + "ip": "2443::2", + "port": "443", + "weight": "1" + }, + { + "ip": "2443::3", + "port": "443", + "weight": "1" + }, + { + "ip": "2443::4", + "port": "443", + "weight": "4" + } + ] + } +] diff --git a/autotest/units/001_one_port/055_two_rule_three_ids/001-expect.pcap b/autotest/units/001_one_port/055_two_rule_three_ids/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..e7c11fe36277c0c92bd46e12e09bfaa0403099eb GIT binary patch literal 400 zcmca|c+)~A1{MYw`2U}Qff2?5(tc13qyz;883dJ#T|yff7*g8qCIE#PMA+;V6nO9Q z0GX@Lf&>^CKzs%U69@-r*x>+%02n8LNr9oI62>FibfBAvHNCltWYd8f@R%+JGY{*DDd9p z0Ww#g1qm=PfcOjyCJ+wLu)_fi0WeMglLA9aC5%V3=|DFTYkG4P$)*D};4xhcW**q> zn_)aExgEvy<}D 200.0.0.1" +- ipv6Update: "::/0 -> fe80::1" +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap diff --git a/autotest/units/001_one_port/055_two_rule_three_ids/controlplane.conf b/autotest/units/001_one_port/055_two_rule_three_ids/controlplane.conf new file mode 100644 index 00000000..957964d2 --- /dev/null +++ b/autotest/units/001_one_port/055_two_rule_three_ids/controlplane.conf @@ -0,0 +1,46 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall.txt", + "nextModules": [ + "vrf0" + ] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipAddresses": [ + "fe80::2" + ], + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipAddresses": [ + "200.0.0.2" + ], + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/055_two_rule_three_ids/firewall.txt b/autotest/units/001_one_port/055_two_rule_three_ids/firewall.txt new file mode 100644 index 00000000..dd098f76 --- /dev/null +++ b/autotest/units/001_one_port/055_two_rule_three_ids/firewall.txt @@ -0,0 +1,7 @@ +:BEGIN +add skipto :IN ip from any to any in + +:IN +add allow tcp from 2020:ddd:c00:0:abcd::/ffff:ffff:ff00:0:ffff:: to any 80 +add allow tcp from 2020:ddd:c00::/48 to any 22 +add deny ip from any to any diff --git a/autotest/units/001_one_port/055_two_rule_three_ids/gen.py b/autotest/units/001_one_port/055_two_rule_three_ids/gen.py new file mode 100755 index 00000000..8790bfc7 --- /dev/null +++ b/autotest/units/001_one_port/055_two_rule_three_ids/gen.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * + + +def write_pcap(filename, *packetsList): + if len(packetsList) == 0: + PcapWriter(filename)._write_header(Ether()) + return + + PcapWriter(filename) + + for packets in packetsList: + if type(packets) == list: + for packet in packets: + packet.time = 0 + wrpcap(filename, [p for p in packet], append=True) + else: + packets.time = 0 + wrpcap(filename, [p for p in packets], append=True) + + +def ipv6_send(_src, _dst): + return Ether(dst="00:11:22:33:44:55", src="00:00:00:22:22:22")/Dot1Q(vlan=200)/IPv6(src=_src, dst=_dst, hlim=64, fl=0) + + +def ipv6_recv(_src, _dst): + return Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(src=_src, dst=_dst, hlim=63, fl=0) + + +write_pcap("001-send.pcap", *[ + ipv6_send("2020:ddd:c00:0:abcd::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=80, flags="S"), + ipv6_send("2020:ddd:cff:0:abcd::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=80, flags="S"), + ipv6_send("2020:ddd:c00:0:abcd::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=22, flags="S"), + ipv6_send("2020:ddd:cff:0:abcd::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=22, flags="S"), + ipv6_send("2020:ddd:c00:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=80, flags="S"), + ipv6_send("2020:ddd:cff:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=80, flags="S"), + ipv6_send("2020:ddd:c00:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=22, flags="S"), + ipv6_send("2020:ddd:cff:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=22, flags="S") +]) + + +write_pcap("001-expect.pcap", *[ + ipv6_recv("2020:ddd:c00:0:abcd::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=80, flags="S"), + ipv6_recv("2020:ddd:cff:0:abcd::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=80, flags="S"), + ipv6_recv("2020:ddd:c00:0:abcd::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=22, flags="S"), +# ipv6_recv("2020:ddd:cff:0:abcd::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=22, flags="S"), +# ipv6_recv("2020:ddd:c00:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=80, flags="S"), +# ipv6_recv("2020:ddd:cff:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=80, flags="S"), + ipv6_recv("2020:ddd:c00:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=22, flags="S"), +# ipv6_recv("2020:ddd:cff:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=22, flags="S") +]) diff --git a/autotest/units/001_one_port/056_balancer_icmp_rate_limit/001-expect.pcap b/autotest/units/001_one_port/056_balancer_icmp_rate_limit/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..7041da810ceee433e092c97e8ef18487c17049b2 GIT binary patch literal 1281024 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 jycSmEjVa+XuZgCCKYyMc&~5{_p<*wb@U> literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/056_balancer_icmp_rate_limit/001-send.pcap b/autotest/units/001_one_port/056_balancer_icmp_rate_limit/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..aaa46ba37a0a5bafe77f60c0fc5e011cc9036679 GIT binary patch literal 1071024 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 yI3|m%u<{qWz@v_qI52EzD1zG8LAyN80iL9J4 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 z zm2Q;%S+epr-6;F9WaS;YQ5v#j0sz$;xl(M%jfWE5D-~WoMSG{GM)Me!!BIztWBJeU_~Jjc%0hv1H}%bfbKiB`g1+8|6DJ zS@|d3DBotu%D?DF`4&r7{!KT^H(9dsAG%S#!IG8#(v9+UmaBYx+lunFPe}O`-6&sW z$v?}d=|=eqOIAKZH_De;vhrEFQNF~ImCw3rMmHHh;so$Th z)W3I>x)x-muH7hgUCT=S9Y(3YQCX?alqmIiBP;d!80F&&S^fWCcB#+$|0^TvJ|O=r zb>E6o_cU3ldvKJxKg&uzPeiF_4OyvYqbT*YYhe>K!jiz5mHdy{|^8cUf7fckd|mUM?$jju55J7-Xf+M55Gr ziLBK5PLw+Pk(GMrk5cDYvQp=6QR+-iRvK^bsCA^*xEK?6J+2{1Ho5_N1Gi_s=q2P|3H zn{Jf%S+cSZ-6-#|WMyBvQQl?AN<+F)-eJkgesrU}&61V<=|_KT zd6Ok82hxr521`~Bq8sIPmaH61H_B@)SviDmlvi1@awy#>udrn0FuGB;uw>_`N4im#uw4q^ zWTh9~D6?6z(wlCSSu9!ULpRDymaO!p8)XJdR{GJ6GMyzW{pm)T#*&o*bfZjV$;v>w zQKqnDWf0vclUcGdm~NCwELj;sH_AkotPG_aWdci9hS7~Oo+T^8=|&mHl9ds3ql{(A z%1F9V#;|1Nc)C%ZVadt~bfY}Yl9dzbMtO=QD<{#7@+3=EPNo~>36`v!LO06eELk~~ zZj{k1Svievl*d@Iays28kFsRt47yPsVadvwbfY}Xl9jXQMtO)OD`(S<@*qoA&Y>IS z0hX+sOE=2>ELk~^Zj}32vT{D%DEG2t<9b&61Ui=tjAVB`X)xjdCYT zRxY6%@*rG7_I>h~ur_3s^}t_4}CYd1<= z*RoQ7hf(TpR95OUB}#qX$Vz=aMj7=9UCH%XAEoXC^3PKDttfR*la;y$N2&X>tkm;F zlzP^Xm3lUcQqN7YQqOr&>KRa0>X|i4J6iA4I9| z7G$Nq3yD(SlgP@LZLZ{zELj;#H$Te=maL4U8)Z04R>sqfGK?iF6X-@6%953dbfXMm z$;u?UQ3kVQWis6;gIKaMg>ICAELoXKH_8B(tW2XDr9Vqnrqhkmk0mQJ=tk+wl9ics zqx50P$}GB3db4C@Hr*(_Sh6yQZj_!ZS(!^WN)MK-%%dBnJ4;sP(~Z)NB`XW)M(N6u zm4$SpbYaQLBDzsJvt(s4-6)+{va*D3l#VP}SxPrb2bQcXqZ_3?OIDWCjna-KD=X+m zY0Hw8m2{)DVaduWx=~uQWMwtoD6LqsvW9MymMmFWOE*djmaMF!8>Kl*R@T#v(u^f5 z8|X%9%953hbfX-{l9gxaMrp#5l}&V`9LtiG=jcW`h9xV{(~WX8OIBW>8|5gLth`7! zN@JF+Y^EFKNS3U;L^sM2ELnM(Zj{4Wva*G4l*3rE@(SH3hq7elRk~3QVadvCbfX;1 zl9ku#MmdNjD{s(^av)1q-lQAl0G6!0MK?+#maJ^08)bi%th`M(%6=?ad53P4hAdfm zmu{4OS+epT-6;F8WaWLjQTArZ$_I3#?8TCm59vnPlO-!3(T%bPOIChLH_A^~vhp*! zQGU#lm7mj%@*|e4{DN+jAF^cSmvp1-&XSd1(T%bjOIChOH%bGRto(*{x5 zc45iN@90L^nI$W~ryFG_maP1NZj>Eavhqi|QFdU-%Ae>)*`6gUf2JE{JC>~cg>IA| zuw>=0bfbKqB`bfU8|8Z}S@}ENDBoqt%0K8v`3_4~{z*5=w^_3CFS=2_#gdhO(~a^? zmaP1TZj^7ZWaYnfqkNs^Dj(k*qkQcXQa(jD%2!$P&+=)yQNF^GmCw+P@@1B+e3ovM zFR^6hb9AG8ktHjiryJ!9ELo{;lrm+den(O2_a`g$?;WMC1zD+UH%eXCvQmGCQR;70 zR_Ze)N`2nQN_{>?`S?Os|Noa=>$Cp<%J8}m$UjTnx1!WNO;+k29Hs8hvQp0zQR-Pk zR_fU(N35 zI+K%?2Hb?B)cK;U)Ol!>IxCfxI@^s>=f1L1=hRW^3|m&}%son-$ID86e-NdE>tokR>a7(T(x}OIG%#8|8hLtn5QK%6lwX*_UpVcUiL1 zkZzQBShBJo-6(IfWMzN4QMR&Vr4ijIZ?R4$WXZ~bbfdh%l9hw#MtPkjD+kk! z@)}E44xt<6RhFzAN;k?YELk~>Zj>!7Svj0;l$Tkuas=HdFR^6hNV-urvt*?)-6$`z zWaTKjQC?ul%F%SAJkOGqW9UYCjwLI{(v7l-B`ZznMtPPcE634|vXLb#P3cD2z><|_ zbfc_i$x3s&QP#0!r3Kw6Ygw|=l5UhWELmwqH_B?3thA;ZWfe zl9hIJqbz61N_)Cdma$}|1KlV~S+dfRZj>b~S?NSK%3_wRbfz0+5ldFO(2cT?B`aO& zMp?j;m2PyS%xB3;ce+vLv1FwO-6(TeveJ`olsPO}=|wlnY?iF_rW<7zOIG^OjWUxZ zD}CuknZc5kesrTuXUR%`x>2UFWMu%|C{tOoGLUYRDJ)qTL^sN0maGh>8)XtpR))}x zGLa=KL+M7Dz><|=bfb)C$;xoLQO2=kWdz+QV_C8?l5UhSELl08Zj@(OvT_35C{MFw zs~k$dZ+F=tg;fB`fFBjdDLrR?edvT$mHJGHQlB@nQlF1e zMtwq8a(&iEsr!KZv($YnO5M|BrS8E|>i#S%^*j-!o;75po{gf^bCaypb6%8s29%Y0 zW{pzMv$9gp-%;w>TvqB`B1*ky$V$BzMX7ftS*drtDE0m)EA_q_rQT&_rQW@x)O)$C z)Hy_=AWtSU;KW64ULyG5xpIawLaJvd68FUm@theoNh zQdz09-6(bLD=T$Q9i`5&Wu?yCqtto4tkm}hQR=$|S*hsoJ z&oY7~E92-!8P1ZG@pPjMW68<{x>1I*WMv}VC_`AXGKp@K!7N#sOgG9PmaI&n8)YC% zR;JR8GJqv3)96O&&ytntbfffR$;u46QTnoEWhUJyeOR(Gi*A(OELoXNH%c#-tjwVs zr6)^P=F*MQgC#5T=tk+zl9l;%qjY1*$^yDky0TAllShBK+Zj{a}Sy@asN+*`A zETJ2vBTH76(v8xAB`eG5MrqHImF0A!v}4K23c69+vSei?-6(BXva*V9l-4X+Sxq-e zE0(ORp&O+oOIFs>jnaZ8E9>Y+Y0i?B^>m{&W68<}x>1_4WMw1WD95p6ny_SL z6Wu7svSj5sx>1f{$;$I|qa4kWl^5tnIf^AKFVc5FI$;wA`qwK+wm7mg$@)MS<{ETjtAG2iT=X9g|h$Sn(pd00fELr&_ z-6*@WWaU?MqwL0#m0#11(tsr^zo8ptSC*{&mTr_?ShDgvx>0s!$;$8PM%jraD}SIH zWk;5*{E=>y9aysRC%RF#XUWQ+=|3H$l7E&@(~a^KmaKe+Zj>*xWaYDTqkM@aE1#nq<%=v?`8?eyUtq~f zb)%FiEA=~yQolc0sekV%buGwBUAs~0x|WstJB(6)qq0(;DN*Y4Mpo+cG0MjmvioUS zpY{J&hShyQ{#ok26{YTJvQqcpD0P39m3p3tQqLN)QqM+F>bXf)>Nzh;Jp;;0J+nrs z=UG{)=kF->Y%VMHE)k{PGi0USi=xy!ldRM`UX*(Ola+d3jZ*KjvQqEfQR=;1R_Yuf zN}VytN}Y*Bsq+$9sq>vEb@n4GbygLn&aq^r&fTKanVhUN;3gcU&KG5+&O@WrS*fhl z*>03N_m!18r;bu**s@Y*?osMIURLV+gDCagf~?ecAyMjk5?R?}n=APvmaObaH$TgV zELqu$Zj=vLva&bbDDSgmWgogx-ebwizI3C!%aWCbbfdh(l9m1FMtPehEBn)pvXvz( zjp#;sizO=u(2epYOI8k~8|4j_tQ|maH_R8)ZF9R+`g|vW_JyE$BvB%aWCr zbfc_c$x17_QC72Lr8V6st5~wqhHjLVELmwwH_8f@thA#WWjRY$+S84)j3p}_=tfz} zl9i5hqby;`N+-He7PDlfGu`maGh;8)ZC8R)*7! zGL9uHBj`pM%aWCmbfb)6$;$C`qddcsl@sVjd733FC(@1b6iZf4q8sH&maLpiH_8(% zSviGnl*d`Jaw^>@qgk?Y8r>+5v1H|Rx=|iw$;ugYqddZrl{4u^d6*?DXVH!F5KC6h zrW@r!maLpZH_8JnSvi+(l>1q-avt3%_pxN<#M`FZe_{JD7sN@VaduBbfetN zl9emzM!AV4D_7BtawAJtuBIF129~T`LpRFxELpjhZj|d-vQphBWy(tZj-u4>Pgd&R zJ4#&(vQpP>l)A2ErTz}1)ZeJA)MrYR`n-{q`h1Ks>Jz$>>$5&e-3R2KrS4l%>YgSm zbq|hG_h(tD=ZPrwtRXA)Y!s!Qn`EV)^PMyYdOS*dgCD0PM{D|O}` zrOxAJrM^FiQr|7eN_`g+rM@STl`-2~$s<{^GL~+BmJuvj8AmtDaF(o$ryFG$OI9Y( zjWU!aD--EP8N!m4NpzzOX35HAx={wPWMvB7C<9rtGL>$W0W4XWMmI`-maI&t8>Jsh zR%XzR(w8MGGwDX@!;+O*bfffU$;xcHQF^gtWe(jaJz26cmu{3EELoXHH%fPwtjwny zr5j6D7SN5-l_e_+=|<_ol9fetqjYA;%3``vI9 zET7&`*fr1&61T5=tkL#B`Y7&jj|_8Rz9K|We=9D z{FH8#pRi=*XLO_dm?bMeryJ!*ELr&l-6%g~$;vP3M%kSuE5D)}WjB_r{F-i*1}s_m z4c#cavSj7AbffITl9k`ljj}UKR(?-6%1$g<`2*c3JF;Zuk94E#z><|e(T%b_OIH3& zH_CP_S@{dyC_iAy%3tY5`94cl{zf;-_gJ#>ce+u&%aWCU(2epPmaP1fZj^7cWaVFU zqkM}cEB~e&<(n*7`48PF-(bngf9Xc~I?Gi)zR^ed+9#xZif)vzvgDuT({!VJg(WMW zp&RAPELr(1-6&sT$;#*GM)@L3Rz6QR$`@F&Qr#$J%1Zr?qSWtCR_fn7N?i-GQrB*j zx~^rV{tlzm->9tAXG)a%ypfgqe2nt(g{=PnFT2%e{r{Drbsvy_mb!06se78N)IB&# z-JfNpo+qNzvxcnHvr&|KZjzOH&WlpdfU;80tWoNDR#xiyJ4!v9%SydVM5*@-S*iD; zDD}=HEA@^SrQZK!rQTPg)Vr*#)Vp_-dM}riI!B07XAH7ZXChJRyhK*&d?!ks{m4q4 zRYj?DELo{@wP;DWu?xkqtqF;tkju%lsb=> zmHPf5N`1E=EA?GSl=_}TR`%HDO8$r?D|^z-&+;KlR`#MB`gby`z%@6hi;Vj zShBJ&-6-#}WThe9DDSXjWk0%6-e$?l{&b^kWywk-x>4R@$;ttAqrAzIl>_NUd4nY@ z2hol4I!jg#rW@romaH5?H_EFlSviz$lvh}?av0qxTUfGkINc~Ovt;E6x=~(Y$;y#* zqikl$N@KcFUS!G2QFNocz><}t=|*{;B`e3!jq)5zR*t0`WfMzQn$V5%EK637qZ?%- zOIDiFjk19yE6wOeS44$WThqDC~H`<(u!`B)htShCWKZj{+9S?NtT z$}EH)0J>48vSei--6&I7vNDKnl*uev z8B90IB$liUp&Ml)OIC)`jWU5HE5qnU8PAfH;dG;nW68=0x>3fmWMw4XC}UW%ay;EA z&#+|W1iDe4X35HlbfY}Ql9iL_MtPDYD<{*9@&rp(PN5s+ah9x{N;k@AmaLpcH_Bry zSvj3zat7TfkFaFrOuA7XX35G~bfY}Pl9jXRMtP7WE9cOS@&HR#&ZQgWewM79 zM>ooSELl09Zj^gjvT_04DEF{ru4`GTzr!f?H!3Uj znG&TwZ)BxDAES)=gs$ZJtdCOn0r_XC`&N{?r^!m)gQL{_Syt+KB1%1L$VxpMMXBc| zS*ho|DD?~|EA`A8rJiSHrJlc|)U&y))VoBKde4xRdM}Dn?@Y2%?|4z_{ZCfveKktG z%gRcdWTnn`qSV=stkhXmlsdfBdW>YO@CongyLow-M;^LSaQ?+>EXcMGyo--Se}?@453 z%r;l@NS3UOrJJ8+1WQ)N(Ty^kB`f3UMj6JEl?imC3}wm6M7mLiuw-Qt-6(@uvND-& zltC<6nL;Bo|l8FZucWy#7+x>5SDWMvlJD7{&- zGMjFcUMyLeLpMrKmaNRB8>I(JR_4)-(w!wM^XW$E#*&oJ1xr@e(T&oaB`fRcMrp>9l?`;GG-b)kM!Hds zW68?1bfYw3$;u|WQI2KF%5!w19K({8=jlc{nk6eQ(2a5wOIBW_8>KNzRyNa(awJPu zUZNZ22$rn8OgGBmELqt?H_BlwS$TzSltWpv@+#dZhp=SjHM&s_X35IybfX-^l9e~; zMmdlrD{s<`asW$K-l7|&5ldFK(v7k|OIF^d8)ZM1th_@vN<)^cyh}IAzARaJk8YHG zShDgy-6(srWaR_8QTAfV%7=8L?8%aqkLX6(gC#3Jr5oiZELr&(-6%h1$;!{^M)?s- zR(?S@$`4tx@=Ll=c4x`TujoeEjU_9;rW>UJOIChEH_EOoS@|v9D7&y^<#%+W?97st z-_wn<6H8Y9KsU;cELr&@-6%V-WaUqEqioNTl|R#svK>oS{z5m(4_LDDSGrNY&ytnD z(T(ywmaP1pZj|q`WaS@pqkM-YEB~Y$<=ZS-`4`3H)a+QxCC!&1q6H-1!H_BI8^3U>Vx>3Hul9kWUjq+udtbCSklrOPl<#TkSe32z9 zpQjt;3oKcwZj>@*rG7_I>h~ur_3s^}t_4}CYd1<=*RoQ7hf(TpR95OUB}#qX$Vz=a zM)~+cR{#H(-Rrad|H_cM56C}D-M6CDJxx~X9vr3a&$3d_6H)3}Lssh9C`vsy$x1!v zMX6^%S*d5%DD^xmEA{*xrJl`YrQRi?)O&`k)O%5sdS{ZAddG`W?|-sV@2gSjT~=1= z-8)LXm&;0>BSfh)23e^yktlUuA}e*i6Q$06WTnokqSQH-tkk(%lsc1>l?L2|qtyAL ztkijElsYSwm3kSAQs=(1Qs>lB>I_>}>dZY#oyW^ceSZ+8zFUx$`Yt3&eNQ4Qdu($h zf5eiNJ?Z9W`H&?md(n;Z0ZUf)rW@sbmaObUH_Ce~S=pCvly_OO(vWVHcUZErAKfT# zvt(s|x>2^WWTg?^C~vW344# zWTge&C~H}=(vohJH7r?aMK{W7maMd<8)X$sR@%^wvXUh$ZRti?!IG7BbfYY1$x3^= zQI@e}r32k4OIfngk#3YFELrJ9H_Bp`taPRuWf4nOy3mcXkR>Z!=|)+=l9g_Bqs(W? zN_V3flWMu^1C}UZ&GLmkTF)Ud*o^F(9Sh8{g-6&79WaUJAl4?8$;!oaquj}ol}qSGxq~Gum(q=LJ4;qBqZ{QmmaJS(H_ELnSs6t) z$}KEexq@z#n_04QCEX}Dv1H{cx>0Uq$;#Dqqujufm22omxt=8}*V2u09ZOcK8>LKH zsoznQ`u)jD{d-5LYe81(+Kp1zwXD?NVU+qCm6iHTiBg|8vQnRqQAT}2S8{#UN2&XO z{Ik@3D@xtdWTo!GQR@CIEA>1PrJglprJjwV)N_-p)N@{xdIpr0dS;DM&$F^p&)-q% z*<4oYT_Q@oXUIyu7e%ReCRwR>yeRelCoA>78l~Q4Wu@M|qttu3tkgL|lsaROl{yoN zQs*VIQs+BS>g-2W>Z~eCony&Lox4S;GdWoq%{@3uoiEBtorgxLvr<{9v)w3l?kg*G zP93Gruw|vr+@sWaysXss2T|&~1zD-@LZa07B(gGQn=5%FOIF6x&CfD|B`f3TMj6hM zmGN|=3}ea41iDd%vSei<-6%s?vNDNol))@nnM^mzAeO95p&Ml&OID`RjWU2GE7Ryk z>Ccjt>2#y?W68=4x>5SFWMwAZD1BJ6GK+4M-Yi*}O*cv}maNR78>J^pR_4-;(t{-{ z^XNwD&XSe+bfa`*$;tw{QM$5ZWg*=tU0AZRh;Ee5ELmAhH%cd#tSq4$r6WsLmeP&V zfh8-;=tgPJl9lCjqqJkm$_lzs+OlM2CEX}(ShBK;Zj{z6Sy@dtN-LJEtf3pFB}-P; z(v8xBB`fRbMrqEHmGyL^G-Jui2D(w2vSei=-T&2gSHX6bX%~fmtQ&XNpmBE>+$DGv zhi)9Yai_a+cXtTx?rw2+5AN=NF{{R#;(p|E-i)Wt$vS(j_3ev9>CKXrp>(74V#&%d zx>0(vWMw$rC_PxRGJK5tRz}l}(uE}}W9UZd%#xL{bfa`) z$;vpoQ980@Wjx&|9ayq5fo_!cELoXIH%dE}tW2UCr7cTVCew}5h9xUg=tgPHl9j1+ zqqJhl$~3xBTC!wiI^8HOSh6yMZj|OMS(!;UN;8(M%%U5mDN9yn(~Z)EB`b62Mrq8F zmAQ1IG-AohJi1XDvSj50x=}V^$;yXxqioEQm5=B~*@z`8AJdJpAxl<1p&MlbmaKeA zH_G}fS^11^lm;wW`J8T)^;oj<1>Gp?vSj5;x>43)$;wxBqpZ!6m9ObWS&Jnr-_VV+ zCQDYnr5j}pmaKe7H_GZPS^1uBl+{?W@&nx{tFmO}N4il~Vadu*bfc`yl9iw7Mp=m^ zE5FcvJl-UOS9yk zWnsEemSV}uB6OoH$&!^t=|)+CB`b^3jj}jPR{lme%HLVCQr#$J%1Zr?qSWtCR_fn7 zN?i-GQrB*jx~^rV{tlzm->9tAXG)a%ypfgqe2g;xLRSC(mksN){!e9a-3R2KrS4l% z>YgSmbq|hG_h(tD=ZPrwtRXA)Y!s!Qn`EV)^PMyYdOS*cgPD0PM{ zD|O}`rOxAJrM^FiQr|7eN_`g+rM@STm4<)0lIO8xr4ilyEOS}1(wJ_PIV@ReLO056 zmaH_T8)X(tR+`a`GLt1M&FMy&!IG60bfZjX$x2JQQKqqEr4`*MQ(3aonr@USELmwo zH_Bv|thA*YWfDtP+R=?NktHkb=|-8rl9dj0ql{=B zS?NMI%4n9Xbfp_*6iZgR(Ty^aB`e+OMj649l^%4X3}?woPr6Ztv1Fwe-6%s@veKJw zl=oS((uZ!8_gJ#BDcvaVvSej5x>4R?$;#$*qrAxud-xiJGxO`Vadw&bfdh?l9e6kMtO-PD?8GS@*+!C zcA^{Q1(vMrOgGB&ELquwZj|R(veK7slxJD8vMb#v&#+`=H@Z=tX35I#bfY}Ql9fH^ zMtPDYD|^z7@&rp(_M#i*ah9y?O*hJ8ELrJCH_D?dS?NzV$|EdU89+D6!z@`DNH@wu zELj;uH_C%7Ss6?>$^$G}*@teF`&qKGFWo5jv1DaGx>4?B$;$q8qYPom$^mqv+{2QU z1L;P&nkAO)ObCl5Uh6S+a5z-6%J(WaVhOQLbmn$}x1KT*s1?W9de@ zmL)6yq8sHJmaP1nZj`H8vT_{VC|9v$<#@VLu4Ku|33Q`e!IG5|=|;JnB`YVi*GwDV-pCv12 z(T#E*OIFUN8|7SPG)>P9J3R_b>YrG9_1Qvcpj>ROPMx^|<~ zbuBCPcNnGqMrEZwQ=-)8jjYt?W0cbu(3M=D^-=0RApb0N--=TAG+C*8aFn_~%St^@ zM5$*DS*d5EDD~VVEA^ZgrJez0rJh-%)bp&Y)bn?gdN!ApdY6b&?-{aE??qASok>>e z9WP3~|H(?duSThNSy`!f?P${nZs8srrOp>+rOrd6)LE&l)Y)#7I`@^8I;W0OXV|h*XYNtzJYH7n`-3R; z-GZ#tcOg;gdlFf>`!84Wfh<|Mhi-nB16Z;$gl?4mS+a63-6;F9WaU1(QTAoY%Kdbs z?8B0k2k1r_%#xJ{=|&mEl9h+(Mj6PGm51p@8Nia2N9acB&ytl#=|<_tl9k8kM%kMs zE05ESvKLEMo}e3LPnN7aNjJ(KELnMqZj{|wvhpIUZfjkN0zL-L^sL~ELnM(Zj|j=vhoVuDBH1Q- zwq?o6YjmS*!;+QP=|R^Fr=WlNTx>0(uWMvrLC_P!SGMsLd9xPcIK{rZwmaL4V z8>JgdRz}f{(v>AEqv=NJ!jhFSbfa`;$;w!|Q97|?WgOio9a*w6o^F&5ELoXAH%fb! ztW2aEr5#IFCee-3mL)5b=|*Y8l9efRqqJtp%2c{hTCrqh8r>)@S+X*nZj=@*S(!mM zN^_R1%%mHo8B11X(T&oSB`dS(Mrp#5l{s{yG-k=lT)I&jv1DZ)-6#!Nvho4lD4Vck zcd`34)1D33OPB+SWELr)2 zZj^OdvhpR}DC@9f1&7$;zU1qb$La zmBr{rS)3&+f1?}a?<`rVZj>@*rG7_I>h~ur_3s^}t_4}CYd1<=*RoQ7hf(TpR95OU zB}#qX$Vz=aMwx#htN;JYM)g_$r!uJS1M<&O_pK;(Pm`6p2S=&cL00NaBubr^$V#2>M5(hMS*f$CD0Pk{D|PM`rOxDJ zr2#kLD0RLlD|H?krOrxarOtMv)VZ&$)H!vOI>VNgda;aB=kc;q-ycM&?-pdGz6*&` z-;>Bn!@pd~^H{Rdh;DwCxhz>}OgG9LmaH_P8)Y_2R+`d{GK(cE&FDs%$&!`kbfe5* z$w~{lQKqwGr6t`c(^#_7if)vtELmwyH_8;2thAvUWim@v+R}|Oi6txT=th~yl9l#! zqfB7QN(Z`8#x(v32TB`e+NMj6SH zmF{$-j9|%154ur?vt*?w-6+FYveJugl%XtH=}kAv`z%@MLpREMELqu4`VadvYbfetOl9hw#M!Ab6D+kk!awkhx z4xt<64wkI^gKm`DS+ep^x>0Up$;zR0quk1pmBZ*pxrHSwhtrL6GfP&Epc~~TmaH5} zH_DAHSviVslp9#Gax~p2*Ry2h7`joeW68>~bfa9$l9hkajdBf3R{l*l%GE4cIgW0W zt5~vfJl!Z)vSj51x>2rR$;ydzqg>9Cm6Pa3xr`+%C)15`DN9yPp&R8AmaLpgH_F8< zSvievl#5uhays287qVpK47yP+V9CmvbfcWll9jXQMmdiqD`(S2fA1)DEyzk;yHV=8mX-QDj8cE2vQnQZQR?$XR_gOH z%IOQ}O0LiPD0Lr@f0nv$MX7t5tkgX?O5LAjrJg6E)U$@H)U#2PdTx@Hdd`bd&w#R0 z&#Y1Ec~(~H`8!HIo6AbQOGK&n3|Xo7qA2ywBrElf7p30+WToC$qtv^stkk=AlzK0h zl{!a=QfCaZQfDGj>byi&>U<|ko&Cs4omEAtb1Ye@bGImUCMPSma1V}B=ZmsZ=b=&R ztW;L&Y&S}s`^rk4Q%9*YY+0!@_b7E9FDv!^L6rJ#L00O!kSO&%iLBiHmn-=|maN=E zH$Te(ELj;sH_HAjS-F>Pl>Jz;av$9&`?6%^e!5ZiVadt^bfXMr$;yLtqYPrn%0qOc z3}ng5!*rtzV9ClObfffV$;zX2qx56R%42k+?9Gyu$LU7dizO>h(2cSuOIDtw8)Xlc ztUN_G%I+*#d75sN-B_~n4BaTZvSj61x>5SFWaT-!QFdX;%JX!i?97st7wAUWi6tv9 z(v7ksOIBW@8)XNUth`J&%JwW-d4+D2?O3w%D%~jCvSj5ox>2@a$;#_=qioHRl{e@{ z*@`7AZ_0(w zWMwGbD7{#+GK_ANo-A1zPB%&qmaL4R8>Kr-Rz}i|(v2l6qv%HI%954Qbfa`($;ueI zQ983^Wh~t&omjFmj&78WELj;(H%bSVtW2OAr9DelCen@4jwLIT=tgPFl9kDHqqJek z$`ra$TC-$jD%~ipSh6yWZj_cRS(#2ZN(+{(%%B^kIZIY%(v8xLB`dS&Mrq2DmDzNo zG-1ig9J)~&vt(s1-6)M%vNDful!h!>`G9VeO<1z>A>Ak&vt;EXx=}V_$;!ucqio2M zl~3qK*?=W0pVE!8K1)_UqZ_3GOIALo8)ZF~tb9Q?%DOCB`I2swby%|U72POnvt;FK zx>43*$;vl$qpZo2m2c@rS%W1j-_eb-I!ji*ryFH8maP0hH_ECkS^1G}lvP-=@)O-C zE3;(fXSz{VV#&%cbfc`ul9gZSMp=O+E5Ff=vOG&xey1B{IhL&aK{v{>ELWNT02XDL z1*9xQH_Fm1`Da;}Zj_~1va$%>C`+OymS*gFnDD^igEA^QYr9N+Dr9K~{%)gM;|Nmv<`mFy` z8CdrL`Ddy7R+PG@$x7XWqtyLbR_b{oN(ZgI(LgwXL7RAfSYiXI$xBPIuDIfXQi@IXS-4A z+*elWoH|OKVarOLxkst2pX+by2be62Nq#I=#OIBLZjWU%b zE3N59nZlBlHguy*X30uhx=|*vWThS5C=*$-(w=UV2`pLZKsU;GmaKH78)Y0zRyxs* zGL|JPo#{py!;+OQbfb)B$x2tcQAV+3r5oKSBU!T2ooR<@%X`phzQ!H88gKm^3S+cSx-6&76WMwb9Q66W>%HDLNJjRlhesrTe%954-bfY}Nl9d5; zqdd%#m4S4lJj9ZfL3E=$$dZ-8bfY}Ll9hevM!BCQEBn%oavw`p_M;o+UY4xvPdCaC zmaH5=H_AOMSvinyl)G87auD4pcd=yUV7gK6WXZ}QbfetCl9hkZjdD9nR{lvh%55xJ zIh1acTUoMl7~Lqhuw>0Us$;uIQquj)jl_Tj!xsfF+N70RP14~wprW@sYmaH5@ zH_CM^Svi(&lxtbC@-Mnku3^c_zv)J~nk6g8(T#EyOID7j8|6xtteikM$`veGIgxIZ z%UQB=65S}5v1H|Bx=}7=$;v5oqg=w0l~d_PxtJv@r_qga5ldE1ryJ!$maLpXH_8Pp zSviw#l=E4#au(ev=donvY`Rg-Wy#8a=ten*B`g1>8|8m2S*dQ6GG(QHM^WncCoA>u z9i^@XS*dF`N?q5oQh$e0>Tgt5>N6!uecs4QeLhAxeF0s`^;sXK?gR4AQunPWbx)I( zx(7$8`?IXn^F)+-){vEYHi}ZuO|nwYc~R;aP*&=hHA+3t%1S+dN2zCXS*dr4DD|Ep zEA?I!rQVrjrQY$P)cc>T)cb0bdY6@zdiRb}@8z;m=Lk{ij6qiFOe9L3m&i(;??kDy zA6cohswj1iB`bCA7NySQWaSp_!BOgbQC8|aG)kS7%1WK>MyYdOS*dgCD0PM{D|O}` zrOxAJrM^FiQr|7eN_`g+rM@STmAn6PB_GI=m3!#sXE}f+D?{i;*`FmV_tK5BA4^v5 zqZ?&kmaN=QH_ARNS$TkNl))@nd5~_DK`dE$h;EdDELnM&Zj=EmS$TwRl>RJPd6aIH zek@sejBb>@S+ept-6(spWaSCEQTAlX%9C`X?7@%1d;k?7)(hm+3~?o+T@< z(2cSkOIBW`8)aLTth`1y$~G)nd7W;Qty!}22HhxIv1H{2@d$;w-Fqin&FmAC0e z*_A;ee33Q{hXUWP$x>4G(WMvZFC~aA?GMR3aHY{10LN`ilmaI&r8>JOXR;JO7(vl@B z)9FTO!IG63bfYw9$;wQ+QJS%2Wft8iOZ0(2cSQOIALl8)ajbtb9Z_%0?_%`Iv5$4Oz1C3Ee0guw>;^x>43=$;xMRqcmX2 z%I9>WtjCg-FX%>DmnAD-(v7kXOIE(38)a>ltb9#3%33U0`G#(kHCeLqE!`+;s zx=~hV$;$V1qpZe~l^^IvS(PO#Khlk|3QJagq8nvpmaP0tH_A#ZS^0%-loeUB@+;ja zE3jncH@Z=lXUWR%bfYZCl9fN`Mp>5SD)S%nqAat3l!fR-Mh{zhe`K2xI9=Z&n?=VO%l7qa^Qzid*U^?xb@>OLU#h*IwvvQqCwQR1I*WTiLVDDSgmr4QXG@3CZM zQ@T;!Wy#8Bbfdh(l9kQrMtPehD_hWw@)k>0wxk>7O_r=|MK{VDELqu_Zj{$qva$`` zD6g?(Wm~#YUS-M3c66h>!jhHk=|*{(B`Z77jq(ypR(7Nt_j)p3oKdLnQoNl zS+cSV-6+qoWTh|ND9^HFWmmdUo?*$#ZgitO&61Vf=|*{qB`bT-jq)T*R`#SD_s=q<1AU(n{JfHShCWOZj?t^veKV!lt);yGJtNBhgq^RkZzQRSh6yRZj=XEvND)% zlm}R{vJc%T_p@YWU%FB5W68>XbfetMl9m1GMj67Al>_KTxrZey2hxplH%nFyq8sHd zmaH61H_DwXSviDmlsj0m@(;REZfD8LKj}ufjU_9G(v5N}OI8k}8|4<3tQ<}^%FQfU zIf8DKn^>}PB;6=CvSj5bx>0Um$;#1mqg>CDm1F2exsD|($I^{*ElXDZMK{VdELr(C z-6&VHWaT)zQLbXi%JFogT*;D^6X-^{f+Z^_(v5OCOIA*z8|5;Vtei|Y%B3t>IfZVN zOIWgUD%~g-vt;Eox=}7-$;#<;qg=?6l{4r@xqu}rXVQ&wK1){4q8sHrmaLpjH_Evz zS@{p$DCe+b<-c^J{EsCo)s0f7tkmx)O8x$1rT)F6)U_Zhb?ru}>snUo?=VXJjmk=W zrbMaF8(FE($0(;SpewmP>!Z|tK>k_kz7?hJX|huH;3#!}mX&&*h*HlQvQp1RQR=x# zR_Zw~N<9P0NCrOvTrrOw@=)R~;D+`>IL zN}VstN}Y#Bsk2g9sk7ZEb?z%Gbxs|n&ah>r&fKHadAzLD_Xknxy9HUP??R%~_aw4% z_g}8$16i_i58eDM2e4#i2;C_Avt;F7x>5FH$;y3nqwLF)mHX*N*@q=7573P=m?bL@ z(v32RB`XinjWUoWD-Y9+GJqv3kI;?MpCv1g(v8xOB`c57jj}gORvxDtWiOVjJV7_g zo-A2;l5UheShDgI-6*@WWaVkPQFdd=$}@DM?8=grXX!@i%aWDn=tkLvB`eRBEwh_vuFI&61U&bfffQ$;vRgQF^juWjNg^Jy^0bf^L-VELj;zH%d2_tc;=?r7KHT zM$?Vbg(WLv=tk+xl9jP^qjX})$~d}FI2v|`E1G`dk*vSejC-6$`HXIq1}s_moNko$ShDg3-6-p_WaUe`QPyF} z%2#xwtj&^@ujxivizO@H(2cStOIE(68)Xfatb9i|%IYjx`JQf+)mXCf1KlXAvSj5) zx=~hP$;wZ3qpZx5m7nQGS&1bpztD}cB1=|&r5j}hmaP0nH_GxXS^1rAl;v2m@(0~0 z%d%W${=;OHWfqXK5Zx$Cv*e#;VY*S4V#&%PbfYZEl9fg2Mp=R-D~r*MvN%gt{zf;- z-&wL!-6&fbv`T??{O*KU-$u4SeE4x`lHsI1gyN|gG%k(K&cL00NaBubr^$V#2>M5(hMS*f$CD0Pk{D|PM`rOxDJr2#kLD0RLlD|H?k zrOrxarOtMv)VZ&$)H!vOI>VNgI&+Uw=kc;q-ycM&?-pdGz6*&`-;>Bny^2Sf$8{|$ zjp#<1%aWDGbfe5+$x0KtQD(Dbr77JgvskjyjBb>fELmwzH_8l_thAsTWjae%TGEX& zjU_9s=th~!l9kqUqfBARN*lUSCbMLvE!`-SShCWNZj^~ES!qu<$^@3Ibf6n$JWEzO z(v32XB`cliMj6YJmCkgdjA6-27rIeKvt*?!-6*42veJ!il#wi1=}tGw2$rn$pc`d4 zOICW)jWUcSE4}DO8OoBC-gKk9&ytlsbfdh-l9f&AMtPSdE1S`c@(xQ@Hm4iqZI-NT zK{v`_9ilODtL0k#3Y1S+cSd-6$`xWMyZ%QJ!bX$}V)HJjarizI3BJ%aWB{=|*{m zB`dqpjq)^0R(7Ww_IomlPp=;lWvqJShBJg-6)Tx=|ix$;v>wQ66H+${@N?9%RYNV7gHrV9ClpbfetQl9hewM!AnAEBn!n zaxY6(_NN0Uo$;y#*quj`nm80lJxq&4s zN7IdRJxf-Op&R8omaH60H_EjvS@{>;DA%xL<==FpT+Nb|3AmDA`(xrikzr_+sc zAxl=ypc~}^maLpfH_G`eSviYtl=E1!ayH#4=dxtwKXjvOymS*gFnDD^igEA^QYr9N+Dr9K~{oW6jrUkncJ!{BHJsU--=O$UH=e#KO3@9u0%o?ShXJw_HzoXQ% zxvbQ?M3j2Zkd=Bbic;@PvQqDOQR@9qR_c8KHxR-U69WfzvLJWn^u&MaAZfo_zYShDgW-6%V2@Z$;#VwqioKSm3Qby*^DJC@6wI3DN9z~qZ_3UOIF^e8>Kf(R)*4z(u*Z4!{|oo z$&!`fbfffO$;t@2QM$8aWhC7w-B_|Rif)vyELj;%H%b?ltc;->r87%b#?p<_i6txJ z=tk+tl9lmvqjX@&$^^Pm+OuS3BHbwMSh6ySZj`nxS(!{XN*k7}Oraa4HA_~e(v8xJ zB`eeDMrp~CmFaY&v|!1~47yR8vt(r^-6+jivNDTql%_0MnN2rJ6PB#Zp&O+!OIGI6 zjnarEEA!|^X~>e559mhOge5B<(v7k)OIALj8)YMwtb9y2%7!di`Gjti4Op`BDcvaR zvt;Enx=|XiWaV?ZQPyM0$`^E_tjm&>FX={Ehb1dt(T%b;OIE(78)Yq)tb9W^%9<=$ z`Ic^!HCVFp9o;Cavt;Fax=~hR$;uCOqpZr3l^^LwS%oDlKhce{GD}u|rW<7?maP0j zH_D1ES^1T2loeRA@*CYK%d=$Vce+uQW68=NbfYZGa+UdytWlO(K*~aNqb$vmf0l*m zMp=p_D~r&LvLs7Z7Nr|y36`uZMmNghELr&*-6(%&$x3yjlqoCqJBm`jKUt}N?hnfc>hm$m{0mwA|6dx_XZ@c_zq${|KTF-WqSQT2 zR_Y!crS8wNQqL1n>RCfp>e(ntJvYfpJ?BNKXFyr0XVxh7JS!{p{2is9&1I$DC8E@O zhOE?kQIvXTl9hVLi&F1@vQqD>QR-b*R_fh5O1+oMN}VG_sWS#ysWXu%bzUMXb-oj& z&VFR2&Z?r+IhL%{xm%PvlarMO+=Qdl`J$}Ud1#b6E0vWx+l^A^zOqv1)KTgTTUP4K zJxZO&%SwHJ5T(9bkd^u_BuafxA}bC5awX4W$x6NO=VzI_fRx5`qs(E+KT8w3QD(Db zr77JgvskjyjBb>fELmwzH_8l_thAsTWjae%TGEX&jU_9s=th~!l9kqUqfBARN*lUS zCbMLvE!`-SShCWNZj^~ES!qu<$^@3Ibf6n$JWEzO(v32XB`cliMj6YJmCkgdjA6-2 z7rIeKvt*?!-6*42veJ!il#wi1=}tGw2$rn$pc`d4OICW)jWUcSE4}DO8OoBC-gKk9 z&ytlsbfdh-l9f&AMtPSdE1S`c@(xQ@Hm4iqZI-NTK{v`_9ilODtL0k#3Y1S+cSd z-6$`xWMyZ%QJ!bX$}V)HJjarizI3BJ%aWB{=|*{mB`dqpjq)^0R(7Ww_Iom zlPp=;lWvqJShBJg-6)Tx=|ix$;v>wQ66H+ z${@N?9%RYNV7gHrV9ClpbfetQl9hewM!AnAEBn!naxY6(_NN0Uo$;y#*quj`nm80lJxq&4sN7IdRJxf-Op&R8omaH60H_Ejv zS@{>;DA%xL<==FpT+Nb|3AmDA`(xrikzr_+scAxl=ypc~}^maLpfH_G`eSviYt zl=E1!ayH#4=dxtwKXjvOym zS*gFnDD^igEA^QYr9N+Dr9K~{oW6jrUknc zJ!{BHJsU--=O$UH=e#KO3@9u0%o?ShXJw_HzoXQ%xvbQ?M3j2Zkd=Bbic;@PvQqDO zQR@9qR_c8KHxR-U69 zWfzvLJWn^u&MaAZfo_zYShDgW-6%V2@Z$;#VwqioKSm3Qby*^DJC z@6wI3DN9z~qZ_3UOIF^e8>Kf(R)*4z(u*Z4!{|oo$&!`fbfffO$;t@2QM$8aWhC7w z-B_|Rif)vyELj;%H%b?ltc;->r87%b#?p<_i6txJ=tk+tl9lmvqjX@&$^^Pm+OuS3 zBHbwMSh6ySZj`nxS(!{XN*k7}Oraa4HA_~e(v8xJB`eeDMrp~CmFaY&v|!1~47yR8 zvt(r^-6+jivNDTql%_0MnN2rJ6PB#Zp&O+!OIGI6jnarEEA!|^X~>e559mhOge5B< z(v7k)OIALj8)YMwtb9y2%7!di`Gjti4Op`BDcvaRvt;Enx=|XiWaV?ZQPyM0$`^E_ ztjm&>FX={Ehb1dt(T%b;OIE(78)Yq)tb9W^%9<=$`Ic^!HCVFp9o;Cavt;Fax=~hR z$;uCOqpZr3l^^LwS%oDlKhce{GD}u|rW<7?maP0jH_D1ES^1T2loeRA@*CYK%d=$V zce+uQW68=NbfYZGa+UcH#!;48K*~aNqb$vmf0l*mMp=p_D~r&LvLs7Z7Nr|yiU0e* F{|B%wWK;kE literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/056_balancer_icmp_rate_limit/autotest.yaml b/autotest/units/001_one_port/056_balancer_icmp_rate_limit/autotest.yaml new file mode 100644 index 00000000..9309c67b --- /dev/null +++ b/autotest/units/001_one_port/056_balancer_icmp_rate_limit/autotest.yaml @@ -0,0 +1,24 @@ +## uncomment to try Slow Worker Normal Priority Ring rate limiter with ICMPs which should be processed by slow worker (no real state existing on this balancer) +## most probably ring will be full prior to rate limiter actually being triggered + +# steps: +# - ipv4Update: +# - "0.0.0.0/0 -> 202.0.0.1" +# - "102.0.0.0/8 -> 102.0.0.5" +# - ipv6Update: +# - "2020:ddd:3333::/64 -> 2202::1" +# - "::/0 -> fe80::1" +# - cli: +# - balancer real enable balancer0 10.0.0.34 tcp 80 2013::1 80 +# - balancer real flush + +# - cli_check: | +# balancer real balancer0 10.0.0.34 +# module virtual_ip proto virtual_port scheduler real_ip real_port enabled weight connections packets bytes +# --------- ---------- ----- ------------ --------- ------- --------- ------- ------ ----------- ------- ----- +# balancer0 10.0.0.34 tcp 80 rr 2013::1 80 true 1 0 0 0 + +# - sendPackets: +# - port: kni0 +# send: 001-send.pcap +# expect: 001-expect.pcap diff --git a/autotest/units/001_one_port/056_balancer_icmp_rate_limit/controlplane.conf b/autotest/units/001_one_port/056_balancer_icmp_rate_limit/controlplane.conf new file mode 100644 index 00000000..1f3b3b51 --- /dev/null +++ b/autotest/units/001_one_port/056_balancer_icmp_rate_limit/controlplane.conf @@ -0,0 +1,53 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "nextModules": [ + "balancer0", + "route0" + ] + }, + "balancer0": { + "type": "balancer", + "source": "2020:ddd:3333::a", + "source_ipv4": "102.0.0.22", + "services": "services.conf", + "unrdup": "unrdup.cfg", + "nextModule": "route0" + }, + "route0": { + "type": "route", + "interfaces": { + "kni0.100": { + "neighborIPv4Address": "102.0.0.5", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:00:00:01", + "nextModule": "lp0.100" + }, + "kni0.200": { + "neighborIPv4Address": "202.0.0.1", + "neighborIPv6Address": "2202::1", + "neighborMacAddress": "00:00:00:00:00:02", + "nextModule": "lp0.200" + }, + "lo": { + "nextModule": "controlPlane" + } + } + } + } +} diff --git a/autotest/units/001_one_port/056_balancer_icmp_rate_limit/gen.py b/autotest/units/001_one_port/056_balancer_icmp_rate_limit/gen.py new file mode 100755 index 00000000..33986f66 --- /dev/null +++ b/autotest/units/001_one_port/056_balancer_icmp_rate_limit/gen.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * + + +def write_pcap(filename, *packetsList): + if len(packetsList) == 0: + PcapWriter(filename)._write_header(Ether()) + return + + PcapWriter(filename) + + for packets in packetsList: + if type(packets) == list: + for packet in packets: + packet.time = 0 + wrpcap(filename, [p for p in packet], append=True) + else: + packets.time = 0 + wrpcap(filename, [p for p in packets], append=True) + + +# real is NOT found, packet should be cloned and distributed among neighbor balancers (according to unrdup config) - all of them have ipv4 addresses +# icmp dest unreach +write_pcap("001-send.pcap", + # network unreachable + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IP(dst="10.0.0.34", src="1.101.9.9", ttl=64)/ICMP(type=3, code=0)/IP(src="10.0.0.34", dst="1.1.0.99", ttl=50)/TCP(dport=(1,10500), sport=80) + ) + +write_pcap("001-expect.pcap", + # network unreachable + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="123.1.231.151", src="102.0.0.22", ttl=63)/IP(dst="10.0.0.34", src="1.101.9.9", ttl=64)/ICMP(type=3, code=0)/IP(src="10.0.0.34", dst="1.1.0.99", ttl=50)/TCP(dport=(1,10500), sport=80), + ) diff --git a/autotest/units/001_one_port/056_balancer_icmp_rate_limit/services.conf b/autotest/units/001_one_port/056_balancer_icmp_rate_limit/services.conf new file mode 100644 index 00000000..6f8a3719 --- /dev/null +++ b/autotest/units/001_one_port/056_balancer_icmp_rate_limit/services.conf @@ -0,0 +1,14 @@ +[ + { + "vip": "10.0.0.34", + "proto": "tcp", + "vport": "80", + "scheduler": "rr", + "reals": [ + { + "ip": "2013::1", + "port": "80" + } + ] + } +] diff --git a/autotest/units/001_one_port/056_balancer_icmp_rate_limit/unrdup.cfg b/autotest/units/001_one_port/056_balancer_icmp_rate_limit/unrdup.cfg new file mode 100644 index 00000000..7344f81a --- /dev/null +++ b/autotest/units/001_one_port/056_balancer_icmp_rate_limit/unrdup.cfg @@ -0,0 +1 @@ +10.0.0.34 123.1.231.151 diff --git a/autotest/units/001_one_port/056_balancer_vs_ping_reply/001-expect.pcap b/autotest/units/001_one_port/056_balancer_vs_ping_reply/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..f2d26a202ce383dbcc66e7994eb87f94e6ace759 GIT binary patch literal 184 zcmca|c+)~A1{MYw_+QV!zzE|2X+0Ryh}ofF2u#K4r8l$?^9mY$KBm7SBDmtRm=R9sS8 TR$ftAWngGzY+`C=Zea-ksS_Rm literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/056_balancer_vs_ping_reply/001-send.pcap b/autotest/units/001_one_port/056_balancer_vs_ping_reply/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..87809a9fd9810e5016d1e4e8205bbd0b77f47aeb GIT binary patch literal 184 zcmca|c+)~A1{MYw_+QV!zzE|2X+0=r5L7aD2?a|qHZm}za4@(sFvx(EIxyy+W@Kbw zJVchhY`p`14AQY6H_yD3(Lf$ 201.0.0.1" + - "101.0.0.0/8 -> 101.0.0.3" +- ipv6Update: + - "2000:51b::/32 -> 2202::1" + - "::/0 -> fe80::1" +- cli: + - balancer real enable balancer0 10.0.0.20 tcp 80 101.0.0.1 80 + - balancer real enable balancer0 10.0.0.20 udp 80 101.0.0.1 80 + + - balancer real enable balancer0 10.0.0.21 tcp 80 2010::1 80 + + - balancer real enable balancer0 2005:dead:beef::1 tcp 80 2010::2 80 + - balancer real enable balancer0 2005:dead:beef::1 udp 80 2010::2 80 + - balancer real flush + +- cli_check: | + YANET_FORMAT_COLUMNS=module,virtual_ip,proto,virtual_port,scheduler,real_ip,real_port,enabled,weight,connections,packets,bytes balancer real balancer0 10.0.0.20 + module virtual_ip proto virtual_port scheduler real_ip real_port enabled weight connections packets bytes + --------- ---------- ----- ------------ --------- --------- --------- ------- ------ ----------- ------- ----- + balancer0 10.0.0.20 tcp 80 rr 101.0.0.1 80 true 1 0 0 0 + balancer0 10.0.0.20 udp 80 rr 101.0.0.1 80 true 1 0 0 0 + +- cli_check: | + YANET_FORMAT_COLUMNS=module,virtual_ip,proto,virtual_port,scheduler,real_ip,real_port,enabled,weight,connections,packets,bytes balancer real balancer0 10.0.0.21 + module virtual_ip proto virtual_port scheduler real_ip real_port enabled weight connections packets bytes + --------- ---------- ----- ------------ --------- ------- --------- ------- ------ ----------- ------- ----- + balancer0 10.0.0.21 tcp 80 rr 2010::1 80 true 1 0 0 0 + +# ipv4 and icmpv4 +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap + +# ipv6 and icmpv6 +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap + +# reply even if all reals of a service are disabled +- cli: + - balancer real disable balancer0 10.0.0.21 tcp 80 2010::1 80 + - balancer real flush + +- cli_check: | + YANET_FORMAT_COLUMNS=module,virtual_ip,proto,virtual_port,scheduler,real_ip,real_port,enabled,weight,connections,packets,bytes balancer real balancer0 10.0.0.21 + module virtual_ip proto virtual_port scheduler real_ip real_port enabled weight connections packets bytes + --------- ---------- ----- ------------ --------- ------- --------- ------- ------ ----------- ------- ----- + balancer0 10.0.0.21 tcp 80 rr 2010::1 80 false 1 0 0 0 + +- sendPackets: + - port: kni0 + send: 003-send.pcap + expect: 003-expect.pcap \ No newline at end of file diff --git a/autotest/units/001_one_port/056_balancer_vs_ping_reply/controlplane.conf b/autotest/units/001_one_port/056_balancer_vs_ping_reply/controlplane.conf new file mode 100644 index 00000000..23562586 --- /dev/null +++ b/autotest/units/001_one_port/056_balancer_vs_ping_reply/controlplane.conf @@ -0,0 +1,49 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "nextModules": [ + "balancer0", + "route0" + ] + }, + "balancer0": { + "type": "balancer", + "source": "2000:51b::1", + "source_ipv4": "100.0.0.22", + "services": "services.conf", + "nextModule": "route0" + }, + "route0": { + "type": "route", + "interfaces": { + "kni0.100": { + "neighborIPv4Address": "101.0.0.3", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:00:00:01", + "nextModule": "lp0.100" + }, + "kni0.200": { + "neighborIPv4Address": "201.0.0.1", + "neighborIPv6Address": "2202::1", + "neighborMacAddress": "00:00:00:00:00:02", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/056_balancer_vs_ping_reply/gen.py b/autotest/units/001_one_port/056_balancer_vs_ping_reply/gen.py new file mode 100755 index 00000000..26a4937d --- /dev/null +++ b/autotest/units/001_one_port/056_balancer_vs_ping_reply/gen.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * + + +def write_pcap(filename, *packetsList): + if len(packetsList) == 0: + PcapWriter(filename)._write_header(Ether()) + return + + PcapWriter(filename) + + for packets in packetsList: + if type(packets) == list: + for packet in packets: + packet.time = 0 + wrpcap(filename, [p for p in packet], append=True) + else: + packets.time = 0 + wrpcap(filename, [p for p in packets], append=True) + +write_pcap("001-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IP(dst="10.0.0.20", src="1.1.0.1", ttl=64)/ICMP(type=8, code=0, id=1, seq=0x0001)/"", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IP(dst="10.0.0.20", src="1.1.0.1", ttl=64)/ICMP(type=8, code=0, id=2, seq=0x0002)/"abcdefghijklmnopqrstuvwxyz0123456789") + +write_pcap("001-expect.pcap", + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="1.1.0.1", src="10.0.0.20", ttl=64)/ICMP(type=0, code=0, id=1, seq=0x0001)/"", + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="1.1.0.1", src="10.0.0.20", ttl=64)/ICMP(type=0, code=0, id=2, seq=0x0002)/"abcdefghijklmnopqrstuvwxyz0123456789") + +write_pcap("002-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2005:dead:beef::1", src="2000:51b::1", hlim=64)/ICMPv6EchoRequest(id=1, seq=0x0001)/"", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2005:dead:beef::1", src="2000:51b::1", hlim=64)/ICMPv6EchoRequest(id=2, seq=0x0002)/"0123456789abcdefghijklmnopqrstuvwxyz") + +write_pcap("002-expect.pcap", + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IPv6(dst="2000:51b::1", src="2005:dead:beef::1", hlim=64)/ICMPv6EchoReply(id=1, seq=0x0001)/"", + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IPv6(dst="2000:51b::1", src="2005:dead:beef::1", hlim=64)/ICMPv6EchoReply(id=2, seq=0x0002)/"0123456789abcdefghijklmnopqrstuvwxyz") + +write_pcap("003-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IP(dst="10.0.0.21", src="1.1.0.2", ttl=64)/ICMP(type=8, code=0, id=1, seq=0x0001)/"abcdefghijklmnopqrstuvwxyz0123456789") + +write_pcap("003-expect.pcap", + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="1.1.0.2", src="10.0.0.21", ttl=64)/ICMP(type=0, code=0, id=1, seq=0x0001)/"abcdefghijklmnopqrstuvwxyz0123456789") diff --git a/autotest/units/001_one_port/056_balancer_vs_ping_reply/services.conf b/autotest/units/001_one_port/056_balancer_vs_ping_reply/services.conf new file mode 100644 index 00000000..b68b2101 --- /dev/null +++ b/autotest/units/001_one_port/056_balancer_vs_ping_reply/services.conf @@ -0,0 +1,62 @@ +[ + { + "vip": "10.0.0.20", + "proto": "tcp", + "vport": "80", + "scheduler": "rr", + "reals": [ + { + "ip": "101.0.0.1", + "port": "80" + } + ] + }, + { + "vip": "10.0.0.20", + "proto": "udp", + "vport": "80", + "scheduler": "rr", + "reals": [ + { + "ip": "101.0.0.1", + "port": "80" + } + ] + }, + { + "vip": "10.0.0.21", + "proto": "tcp", + "vport": "80", + "scheduler": "rr", + "reals": [ + { + "ip": "2010::1", + "port": "80" + } + ] + }, + { + "vip": "2005:dead:beef::1", + "proto": "tcp", + "vport": "80", + "scheduler": "rr", + "reals": [ + { + "ip": "2010::2", + "port": "80" + } + ] + }, + { + "vip": "2005:dead:beef::1", + "proto": "udp", + "vport": "80", + "scheduler": "rr", + "reals": [ + { + "ip": "2010::2", + "port": "80" + } + ] + } +] diff --git a/autotest/units/001_one_port/056_multi_cross_rules/001-expect.pcap b/autotest/units/001_one_port/056_multi_cross_rules/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..604b62b0f5887684411577a68bcf900daa6c3e5a GIT binary patch literal 5006 zcmcJTF-rqM5QQf}td!%xA8@g<5f-$t)52N;Mzk|z1?}w4TIDPh8|~Ca!6s-UTB%hm zQ`+XY#Mw($7{STRkSrvZx#Ye~9&g?r`R=^jS78d`>h}REvB2ZT@PUUkO(C6MTHiVb z*gNYr@f6HWuV&e7Zw6ns+u;O2r~#G-1;RRY$YN2iW>9ovrJ;9+SB;|kVHe>$;cDc#~{)&|%#W-aM-9K39 zj537o4h?iJfeF2Mv(OpO5W2s%(8bC$^>j9YN$)bbn)^Gs+OU+c(g;oFVk$*+OSLL+Jj(LKiEu zqo=buLwe5*o?&x_&>IHNusK8MHH&AsoLPxVm(%nbt1(Rzq5CTfo$(BzyIljFnIORJnYG9(J@XW+F?oj2{ketCC`0IO+d^k{?O&x!W$p}g&XJUU zsi(6UN$9!0cm95c&+Tc(=L$+fNY>*6Bc5CX45I51og?8|i6mKM_! z%`jL^D+~R{kKvrlZM}W@ng=CeyJx^V>9m zSBz)1qNB;g_Z~W$OffLhbKTTTysDcy;pR_89|TFJ#-}*K`&+&bzYBvdb*WrxXO@iLCJ40hk=_WyUI79RrogsRC&JY|< zrf+tJ>1Z;g*%_vz$#ksFvM+ZJDN=2>%uzdC?IyAJ zp2Hcnn*_b6@KlI+{#rc82L_G99Zk zxo(oqEYem+*I54FG?i#P-{Z}+0_S_RcQl!TKaV%MpuOk1>F;ams+%4sHn{hSt~ev; z@rsA8BqQj>5eHrCCP5$E@zCL9E_mp0GJjt?;m@ktO(L0|!x^=k1ikBUM(rj+Z`qxp zF{VslL3cPq^ctNZdVS9Dd`FY%o1I}gnoMbShUsWB9ji0BZj#PCG){ut`zAq;mpybe znc}dKp6RAd9}c+`P`kvLqHtb#LCP`mtd*~aVCP|<9 z2gg4j*?^O=f0j9D-6Z!u=Ws^rCP_c;a7ODUN#ALAhW4}Z1eSD%Geob^8KT$c3_nq5 yGV^9RbtcnI|2eZa?Hrt9nQoHwnMn^FO=izZ2!8-k!}6p6 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/056_multi_cross_rules/autotest.yaml b/autotest/units/001_one_port/056_multi_cross_rules/autotest.yaml new file mode 100644 index 00000000..10647965 --- /dev/null +++ b/autotest/units/001_one_port/056_multi_cross_rules/autotest.yaml @@ -0,0 +1,7 @@ +steps: +- ipv4Update: "0.0.0.0/0 -> 200.0.0.1" +- ipv6Update: "::/0 -> fe80::1" +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap diff --git a/autotest/units/001_one_port/056_multi_cross_rules/controlplane.conf b/autotest/units/001_one_port/056_multi_cross_rules/controlplane.conf new file mode 100644 index 00000000..957964d2 --- /dev/null +++ b/autotest/units/001_one_port/056_multi_cross_rules/controlplane.conf @@ -0,0 +1,46 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall.txt", + "nextModules": [ + "vrf0" + ] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipAddresses": [ + "fe80::2" + ], + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipAddresses": [ + "200.0.0.2" + ], + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/056_multi_cross_rules/firewall.txt b/autotest/units/001_one_port/056_multi_cross_rules/firewall.txt new file mode 100644 index 00000000..85471783 --- /dev/null +++ b/autotest/units/001_one_port/056_multi_cross_rules/firewall.txt @@ -0,0 +1,12 @@ +:BEGIN +add skipto :IN ip from any to any in + +:IN +add allow tcp from 2020:ddd:c00::/48 to any 48 +add allow tcp from 2020:ddd:c00:0:aaaa::/ffff:ffff:ff00:0:ffff:: to any 80 +add allow tcp from 2020:ddd:c00::/56 to any 56 +add allow tcp from 2020:ddd:c00:0:cccc::/ffff:ffff:ff00:0:ffff:: to any 443 +add allow tcp from 2020:ddd:c00::/40 to any 40 +add allow tcp from 2020:ddd::/32 to any 32 +add allow tcp from 2020:ddd:c00::/64 to any 64 +add deny ip from any to any diff --git a/autotest/units/001_one_port/056_multi_cross_rules/gen.py b/autotest/units/001_one_port/056_multi_cross_rules/gen.py new file mode 100755 index 00000000..735d7d0d --- /dev/null +++ b/autotest/units/001_one_port/056_multi_cross_rules/gen.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * + + +def write_pcap(filename, *packetsList): + if len(packetsList) == 0: + PcapWriter(filename)._write_header(Ether()) + return + + PcapWriter(filename) + + for packets in packetsList: + if type(packets) == list: + for packet in packets: + packet.time = 0 + wrpcap(filename, [p for p in packet], append=True) + else: + packets.time = 0 + wrpcap(filename, [p for p in packets], append=True) + + +def ipv6_send(_src, _dst): + return Ether(dst="00:11:22:33:44:55", src="00:00:00:22:22:22")/Dot1Q(vlan=200)/IPv6(src=_src, dst=_dst, hlim=64, fl=0) + + +def ipv6_recv(_src, _dst): + return Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(src=_src, dst=_dst, hlim=63, fl=0) + +def block(_func, _tcp_port): + return [ + _func("2020:ddd:c00:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:c00:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:c00:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:c00:f:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:c00:f:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:c00:f:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:c00:f00:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:c00:f00:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:c00:f00:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:c0f:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:c0f:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:c0f:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:f00:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:f00:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:f00:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddf:c00:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddf:c00:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddf:c00:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + ] + +def block_send(_tcp_port): + return block(ipv6_send, _tcp_port) + + +write_pcap("001-send.pcap", *[ + block_send(16), + block_send(32), + block_send(40), + block_send(48), + block_send(56), + block_send(64), + block_send(80), + block_send(443), +]) + +write_pcap("001-expect.pcap", *[ + ipv6_recv("2020:ddd:c00:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=32, flags="S"), + ipv6_recv("2020:ddd:c00:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=32, flags="S"), + ipv6_recv("2020:ddd:c00:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=32, flags="S"), + ipv6_recv("2020:ddd:c00:f:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=32, flags="S"), + ipv6_recv("2020:ddd:c00:f:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=32, flags="S"), + ipv6_recv("2020:ddd:c00:f:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=32, flags="S"), + ipv6_recv("2020:ddd:c00:f00:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=32, flags="S"), + ipv6_recv("2020:ddd:c00:f00:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=32, flags="S"), + ipv6_recv("2020:ddd:c00:f00:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=32, flags="S"), + ipv6_recv("2020:ddd:c0f:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=32, flags="S"), + ipv6_recv("2020:ddd:c0f:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=32, flags="S"), + ipv6_recv("2020:ddd:c0f:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=32, flags="S"), + ipv6_recv("2020:ddd:f00:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=32, flags="S"), + ipv6_recv("2020:ddd:f00:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=32, flags="S"), + ipv6_recv("2020:ddd:f00:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=32, flags="S"), + + ipv6_recv("2020:ddd:c00:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=40, flags="S"), + ipv6_recv("2020:ddd:c00:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=40, flags="S"), + ipv6_recv("2020:ddd:c00:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=40, flags="S"), + ipv6_recv("2020:ddd:c00:f:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=40, flags="S"), + ipv6_recv("2020:ddd:c00:f:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=40, flags="S"), + ipv6_recv("2020:ddd:c00:f:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=40, flags="S"), + ipv6_recv("2020:ddd:c00:f00:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=40, flags="S"), + ipv6_recv("2020:ddd:c00:f00:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=40, flags="S"), + ipv6_recv("2020:ddd:c00:f00:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=40, flags="S"), + ipv6_recv("2020:ddd:c0f:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=40, flags="S"), + ipv6_recv("2020:ddd:c0f:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=40, flags="S"), + ipv6_recv("2020:ddd:c0f:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=40, flags="S"), + + ipv6_recv("2020:ddd:c00:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=48, flags="S"), + ipv6_recv("2020:ddd:c00:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=48, flags="S"), + ipv6_recv("2020:ddd:c00:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=48, flags="S"), + ipv6_recv("2020:ddd:c00:f:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=48, flags="S"), + ipv6_recv("2020:ddd:c00:f:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=48, flags="S"), + ipv6_recv("2020:ddd:c00:f:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=48, flags="S"), + ipv6_recv("2020:ddd:c00:f00:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=48, flags="S"), + ipv6_recv("2020:ddd:c00:f00:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=48, flags="S"), + ipv6_recv("2020:ddd:c00:f00:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=48, flags="S"), + + ipv6_recv("2020:ddd:c00:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=56, flags="S"), + ipv6_recv("2020:ddd:c00:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=56, flags="S"), + ipv6_recv("2020:ddd:c00:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=56, flags="S"), + ipv6_recv("2020:ddd:c00:f:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=56, flags="S"), + ipv6_recv("2020:ddd:c00:f:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=56, flags="S"), + ipv6_recv("2020:ddd:c00:f:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=56, flags="S"), + + ipv6_recv("2020:ddd:c00:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=64, flags="S"), + ipv6_recv("2020:ddd:c00:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=64, flags="S"), + ipv6_recv("2020:ddd:c00:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=64, flags="S"), + + ipv6_recv("2020:ddd:c00:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=80, flags="S"), + ipv6_recv("2020:ddd:c00:f:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=80, flags="S"), + ipv6_recv("2020:ddd:c00:f00:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=80, flags="S"), + ipv6_recv("2020:ddd:c0f:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=80, flags="S"), + + ipv6_recv("2020:ddd:c00:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=443, flags="S"), + ipv6_recv("2020:ddd:c00:f:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=443, flags="S"), + ipv6_recv("2020:ddd:c00:f00:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=443, flags="S"), + ipv6_recv("2020:ddd:c0f:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=443, flags="S"), +]) diff --git a/autotest/units/001_one_port/057_self_cross_rules/001-expect.pcap b/autotest/units/001_one_port/057_self_cross_rules/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..f86cc6dea951c5e5020a1f330b460007e5a9f219 GIT binary patch literal 964 zcmca|c+)~A1{MYw`2U}Qff2?5(tc13qyz;883dJ#T|yff7*g8qCIE#PMA+;V6nO9Q z0GX>+fdm*BKzs%U69@-r*x>+%02n8LNr9nt4va^N>1WPBbP+N=xr!XqLB0k7LZ%zI zL)3vtB149sgplba*>s@0i4FIbxg?to)POtO8F$0X1I20*(4R0sjgUb#y+sLTHYwpw gwA&GelMt)8(+sNH_0A%UCo*J!u}ZAl69pI;0J9x@xc~qF literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/057_self_cross_rules/001-send.pcap b/autotest/units/001_one_port/057_self_cross_rules/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..9a8df6cfc10bd0c35d215ccdcf7c48cb8edad574 GIT binary patch literal 3408 zcmb`Jze~el5QeWsoD>zrxn$SYAA?8-2SF#v(p}S0u;8eZnz{*g*TKQ1qv+(=L5I4D zF7|J!ch;kPL%zOuco32c$-|e2yvO&^d%Q2x6lo2IL?vzby#II5LbATo;3i3ubE3Da z!2vh4IK5q|%noMwvfGs#MA8#&j2edZQd-g`Emx@hshx%1?~mS^L~lNM=h?6T%7~d%P5;iBTkYU9@e2_%0lj(Zp-0RF^xCeO9-lJ-y?yPW!)A^=blA+M znI2D5U?#uw&`~qlnTL*=sqR_nLPpcnF{erBsF{{IO+rV_)a_|vmBnUCFKSxmOunk! z|IC??o^h_Vz#RuaUTh|$uY4;TUVC)Tg!DY|(2M_>ke-d<=q{Dl4x4!&<3aDyG=*!w pT=URTGl%mYI%;N_clTPD86l%-x-q9o=%|@vbDD&Xn%Uws{Q$ES-M9b% literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/057_self_cross_rules/autotest.yaml b/autotest/units/001_one_port/057_self_cross_rules/autotest.yaml new file mode 100644 index 00000000..10647965 --- /dev/null +++ b/autotest/units/001_one_port/057_self_cross_rules/autotest.yaml @@ -0,0 +1,7 @@ +steps: +- ipv4Update: "0.0.0.0/0 -> 200.0.0.1" +- ipv6Update: "::/0 -> fe80::1" +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap diff --git a/autotest/units/001_one_port/057_self_cross_rules/controlplane.conf b/autotest/units/001_one_port/057_self_cross_rules/controlplane.conf new file mode 100644 index 00000000..957964d2 --- /dev/null +++ b/autotest/units/001_one_port/057_self_cross_rules/controlplane.conf @@ -0,0 +1,46 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall.txt", + "nextModules": [ + "vrf0" + ] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipAddresses": [ + "fe80::2" + ], + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipAddresses": [ + "200.0.0.2" + ], + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/057_self_cross_rules/firewall.txt b/autotest/units/001_one_port/057_self_cross_rules/firewall.txt new file mode 100644 index 00000000..59e15fa2 --- /dev/null +++ b/autotest/units/001_one_port/057_self_cross_rules/firewall.txt @@ -0,0 +1,7 @@ +:BEGIN +add skipto :IN ip from any to any in + +:IN +add allow tcp from { 2020:ddd:c00::/48 or 2020:ddd:c00:0:aaaa::/ffff:ffff:ff00:0:ffff:: } to any 80 +add allow tcp from { 2020:ddd:c0f::/48 or 2020:ddd:c00:0:cccc::/ffff:ffff:ff00:0:ffff:: } to any 443 +add deny ip from any to any diff --git a/autotest/units/001_one_port/057_self_cross_rules/gen.py b/autotest/units/001_one_port/057_self_cross_rules/gen.py new file mode 100755 index 00000000..126ef290 --- /dev/null +++ b/autotest/units/001_one_port/057_self_cross_rules/gen.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * + + +def write_pcap(filename, *packetsList): + if len(packetsList) == 0: + PcapWriter(filename)._write_header(Ether()) + return + + PcapWriter(filename) + + for packets in packetsList: + if type(packets) == list: + for packet in packets: + packet.time = 0 + wrpcap(filename, [p for p in packet], append=True) + else: + packets.time = 0 + wrpcap(filename, [p for p in packets], append=True) + + +def ipv6_send(_src, _dst): + return Ether(dst="00:11:22:33:44:55", src="00:00:00:22:22:22")/Dot1Q(vlan=200)/IPv6(src=_src, dst=_dst, hlim=64, fl=0) + + +def ipv6_recv(_src, _dst): + return Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(src=_src, dst=_dst, hlim=63, fl=0) + +def block(_func, _tcp_port): + return [ + _func("2020:ddd:c00:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:c00:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:c00:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:c0f:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:c0f:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:c0f:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:cff:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:cff:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:cff:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:ffff:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:ffff:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + _func("2020:ddd:ffff:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=_tcp_port, flags="S"), + ] + +def block_send(_tcp_port): + return block(ipv6_send, _tcp_port) + + +write_pcap("001-send.pcap", *[ + block_send(22), + block_send(80), + block_send(443), +]) + +write_pcap("001-expect.pcap", *[ + ipv6_recv("2020:ddd:c00:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=80, flags="S"), + ipv6_recv("2020:ddd:c00:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=80, flags="S"), + ipv6_recv("2020:ddd:c00:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=80, flags="S"), + ipv6_recv("2020:ddd:c0f:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=80, flags="S"), + ipv6_recv("2020:ddd:cff:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=80, flags="S"), + + ipv6_recv("2020:ddd:c00:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=443, flags="S"), + ipv6_recv("2020:ddd:c0f:0:aaaa::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=443, flags="S"), + ipv6_recv("2020:ddd:c0f:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=443, flags="S"), + ipv6_recv("2020:ddd:c0f:0:ffff::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=443, flags="S"), + ipv6_recv("2020:ddd:cff:0:cccc::", "2020:ddd:0:3400::1")/TCP(sport=50000, dport=443, flags="S"), +]) diff --git a/autotest/units/001_one_port/058_network_intersect_extended/001-expect.pcap b/autotest/units/001_one_port/058_network_intersect_extended/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..75d8fc7c5e83279a2865c19e674f0c4e82a65e4f GIT binary patch literal 868 zcmca|c+)~A1{MYw`2U}Qff2?5(oRqeqyz;883dJ#T|yff7*g8qCIE#PI0Wql1(lRQ zOekPfP~g2Q0OW**f<+jCW}7l_n8MYNY$6lLLX=%tNihwKu19DCL|DS3mGK1U* za!h$S*hx@dEByoWfCR~I1e^FD2&iTvi-N+LGY&wv0OJt^pl<9c2J?Uf$!-Lj7y#6X zYGM_|CjS4A%S1n*Z6FK;*wUj28+v*KyAh%stPA98F)#~A1TZNuL`{eBASRP;Iw+Qq I+>2p40C8+&5dZ)H literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/058_network_intersect_extended/001-send.pcap b/autotest/units/001_one_port/058_network_intersect_extended/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..f02b4f6677775adc928dd11146362cebf426826d GIT binary patch literal 1606 zcmb`HF$%&k6hMD#5f{NgaSpkHb}yo}UfxeapSSD9hX8bN4&doTd}pcwVUu|(62{m8;C`&uB7p&k31JL}Dm+Su z)ktRoCfE@SioKq)BjV~5_cz3a+0~ASj!j}@PxP^BigtCVs`H(m_}NhsadnnSh9XYQ z(b^GdhZs5&Id3{T5PNuzvfjE=RiC$d?&qovabLecMPx5GA{X&DVnAtGq7Na`N;y6@ z){c@GcZh{Ek@KdbD>3Of=8ldDv>jcEcni&{U2g_o&o|;y?1t^jA2;l`|G1xC&lmw1 RiBDm5s>j&d(ObS9`Wr7$y}1AY literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/058_network_intersect_extended/autotest.yaml b/autotest/units/001_one_port/058_network_intersect_extended/autotest.yaml new file mode 100644 index 00000000..10647965 --- /dev/null +++ b/autotest/units/001_one_port/058_network_intersect_extended/autotest.yaml @@ -0,0 +1,7 @@ +steps: +- ipv4Update: "0.0.0.0/0 -> 200.0.0.1" +- ipv6Update: "::/0 -> fe80::1" +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap diff --git a/autotest/units/001_one_port/058_network_intersect_extended/controlplane.conf b/autotest/units/001_one_port/058_network_intersect_extended/controlplane.conf new file mode 100644 index 00000000..957964d2 --- /dev/null +++ b/autotest/units/001_one_port/058_network_intersect_extended/controlplane.conf @@ -0,0 +1,46 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall.txt", + "nextModules": [ + "vrf0" + ] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipAddresses": [ + "fe80::2" + ], + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipAddresses": [ + "200.0.0.2" + ], + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/058_network_intersect_extended/firewall.txt b/autotest/units/001_one_port/058_network_intersect_extended/firewall.txt new file mode 100644 index 00000000..cfd7d537 --- /dev/null +++ b/autotest/units/001_one_port/058_network_intersect_extended/firewall.txt @@ -0,0 +1,27 @@ +:BEGIN +add skipto :IN ip from any to any in + +:IN +add skipto :SEC_GAP1 ip from any to 2020:ddd:1000::/ffff:ffff:ffff:ffff:: +add skipto :SEC_GAP2 ip from any to 2020:ddd:2000::/ffff:ffff:ffff:: +add skipto :SEC_GAP3 ip from any to 2020:ddd::/ffff:ffff:: +add skipto :SEC_SIM ip from any to 2020:cccc:0:0:1111::/ffff:ffff:0000:0000:ffff:: +add deny ip from any to any + +:SEC_GAP1 +add allow ip from any to 2020:ddd:0:0:5555::/ffff:ffff:0000:0000:ffff:: +add deny ip from any to any + +:SEC_GAP2 +add allow ip from any to 2020:ddd:0:0:6666::/ffff:ffff:0000:0000:ffff:: +add deny ip from any to any + +:SEC_GAP3 +add allow ip from any to 2020:ddd:0:0:7777::/ffff:ffff:0000:0000:ffff:: +add deny ip from any to any + +:SEC_SIM +add allow ip from any to 2020:cccc:4000::/ffff:ffff:ffff:ffff:: +add allow ip from any to 2020:cccc:5000::/ffff:ffff:ffff:: +add allow tcp from any to 2020:cccc::/ffff:ffff:: dst-port 22 +add deny ip from any to any diff --git a/autotest/units/001_one_port/058_network_intersect_extended/gen.py b/autotest/units/001_one_port/058_network_intersect_extended/gen.py new file mode 100755 index 00000000..b557742d --- /dev/null +++ b/autotest/units/001_one_port/058_network_intersect_extended/gen.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * + + +def write_pcap(filename, *packetsList): + if len(packetsList) == 0: + PcapWriter(filename)._write_header(Ether()) + return + + PcapWriter(filename) + + for packets in packetsList: + if type(packets) == list: + for packet in packets: + packet.time = 0 + wrpcap(filename, [p for p in packet], append=True) + else: + packets.time = 0 + wrpcap(filename, [p for p in packets], append=True) + + +def ipv6_send(_src, _dst): + return Ether(dst="00:11:22:33:44:55", src="00:00:00:22:22:22")/Dot1Q(vlan=200)/IPv6(src=_src, dst=_dst, hlim=64, fl=0) + + +def ipv6_recv(_src, _dst): + return Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(src=_src, dst=_dst, hlim=63, fl=0) + + +write_pcap("001-send.pcap", [ + # SEC_GAP1 + ipv6_send("1111:2222::1", "2020:ddd:1000::1")/UDP(sport=1024, dport=53), + ipv6_send("1111:2222::1", "2020:ddd:0000:0000:5555::1")/UDP(sport=1024, dport=53), + ipv6_send("1111:2222::1", "2020:ddd:1000:0000:5555::1")/UDP(sport=1024, dport=53), + + # SEC_GAP2 + ipv6_send("1111:2222::2", "2020:ddd:2000::1")/UDP(sport=1024, dport=53), + ipv6_send("1111:2222::2", "2020:ddd:0000:0000:6666::1")/UDP(sport=1024, dport=53), + ipv6_send("1111:2222::2", "2020:ddd:2000:0000:6666::1")/UDP(sport=1024, dport=53), + ipv6_send("1111:2222::2", "2020:ddd:2000:ffff:6666::1")/UDP(sport=1024, dport=53), + + # SEC_GAP3 + ipv6_send("1111:2222::3", "2020:ddd::1")/UDP(sport=1024, dport=53), + ipv6_send("1111:2222::3", "2020:ddd:0000:0000:7777::1")/UDP(sport=1024, dport=53), + ipv6_send("1111:2222::3", "2020:ddd:ffff:ffff:7777::1")/UDP(sport=1024, dport=53), + + # SEC_SIM + ipv6_send("1111:2222::4", "2020:cccc:0:0:1111::1")/UDP(sport=1024, dport=53), + ipv6_send("1111:2222::4", "2020:cccc:4000:0:1111::1")/UDP(sport=1024, dport=53), + ipv6_send("1111:2222::4", "2020:cccc:4000:ffff:1111::1")/UDP(sport=1024, dport=53), + ipv6_send("1111:2222::4", "2020:cccc:5000:0:1111::1")/UDP(sport=1024, dport=53), + ipv6_send("1111:2222::4", "2020:cccc:5000:ffff:1111::1")/UDP(sport=1024, dport=53), + ipv6_send("1111:2222::4", "2020:cccc:0:0:1111::1")/UDP(sport=1024, dport=53), + ipv6_send("1111:2222::4", "2020:cccc:ffff:ffff:1111::1")/UDP(sport=1024, dport=53), + ipv6_send("1111:2222::4", "2020:cccc:0:0:1111::1")/TCP(sport=1024, dport=22), + ipv6_send("1111:2222::4", "2020:cccc:ffff:ffff:1111::1")/TCP(sport=1024, dport=22), +]) + + +write_pcap("001-expect.pcap", *[ + # SEC_GAP1 +# ipv6_recv("1111:2222::1", "2020:ddd:1000::1")/UDP(sport=1024, dport=53), +# ipv6_recv("1111:2222::1", "2020:ddd:0000:0000:5555::1")/UDP(sport=1024, dport=53), + ipv6_recv("1111:2222::1", "2020:ddd:1000:0000:5555::1")/UDP(sport=1024, dport=53), + + # SEC_GAP2 +# ipv6_recv("1111:2222::2", "2020:ddd:2000::1")/UDP(sport=1024, dport=53), +# ipv6_recv("1111:2222::2", "2020:ddd:0000:0000:6666::1")/UDP(sport=1024, dport=53), + ipv6_recv("1111:2222::2", "2020:ddd:2000:0000:6666::1")/UDP(sport=1024, dport=53), + ipv6_recv("1111:2222::2", "2020:ddd:2000:ffff:6666::1")/UDP(sport=1024, dport=53), + + # SEC_GAP3 +# ipv6_recv("1111:2222::3", "2020:ddd::1")/UDP(sport=1024, dport=53), + ipv6_recv("1111:2222::3", "2020:ddd:0000:0000:7777::1")/UDP(sport=1024, dport=53), + ipv6_recv("1111:2222::3", "2020:ddd:ffff:ffff:7777::1")/UDP(sport=1024, dport=53), + + # SEC_SIM +# ipv6_recv("1111:2222::4", "2020:cccc:0:0:1111::1")/UDP(sport=1024, dport=53), + ipv6_recv("1111:2222::4", "2020:cccc:4000:0:1111::1")/UDP(sport=1024, dport=53), +# ipv6_recv("1111:2222::4", "2020:cccc:4000:ffff:1111::1")/UDP(sport=1024, dport=53), + ipv6_recv("1111:2222::4", "2020:cccc:5000:0:1111::1")/UDP(sport=1024, dport=53), + ipv6_recv("1111:2222::4", "2020:cccc:5000:ffff:1111::1")/UDP(sport=1024, dport=53), +# ipv6_recv("1111:2222::4", "2020:cccc:0:0:1111::1")/UDP(sport=1024, dport=53), +# ipv6_recv("1111:2222::4", "2020:cccc:ffff:ffff:1111::1")/UDP(sport=1024, dport=53), + ipv6_recv("1111:2222::4", "2020:cccc:0:0:1111::1")/TCP(sport=1024, dport=22), + ipv6_recv("1111:2222::4", "2020:cccc:ffff:ffff:1111::1")/TCP(sport=1024, dport=22), +]) diff --git a/autotest/units/001_one_port/059_firewall_tablearg/001-expect.pcap b/autotest/units/001_one_port/059_firewall_tablearg/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..4588786058a3b87ffa9f5c183f89478e414ade6f GIT binary patch literal 606 zcmca|c+)~A1{MYw_+QV!zzE|2X)7oOQc6ln41!9=E}@MK3@11kTp1WNKuYb|_6l<` zGO%9Va-R`sP5?}EfPezSnG-M`1A`ur3Bo{tX_5@sB*D`+xEL83uWmW-C^!XZ7Kc?3 zL<1SR8G*V3$=1yT)D8Cu$u4IG>h>qwZWf?!KeBbR0(JY6t(y&~+Xtqbn7E&kt_TFc V7%OC9ke>k48Ni~z(DH(T0RaDnS-b!M literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/059_firewall_tablearg/001-send.pcap b/autotest/units/001_one_port/059_firewall_tablearg/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..8b65a25f535bab00063bca22d6e4e91118f22b00 GIT binary patch literal 1260 zcmca|c+)~A1{MYw_+QV!zzE|2X)7pZ5L7aD2?cTl1qB-!7*aSGTp1WNKuR6hZi{g- zFfd=;a)6PAfpIrXa{!Y9!>c?Pk7Sb=(M-xE+axA5lXA#5i5bnLY_d&aK{F|fY?D~g zOv)tNBsMgYGDtINk1!V_1MAf-_kpQ^ApoW~KtO@v%n2Befk6+*1YxY{Nd}yr1izGW zF)}jxM(BY|s%GFQ<$&oYM)#>3Al+BDoOcwQ0@Tl86-2gfMxgFMvUM{7b;HAfWS27o zb^DWTHw#d=AKAKDfx3Ok*3Aag?E}+IO!;y88l?O6 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/059_firewall_tablearg/autotest.yaml b/autotest/units/001_one_port/059_firewall_tablearg/autotest.yaml new file mode 100644 index 00000000..41862999 --- /dev/null +++ b/autotest/units/001_one_port/059_firewall_tablearg/autotest.yaml @@ -0,0 +1,7 @@ +steps: +- ipv4Update: "0.0.0.0/0 -> 200.0.0.1" +- clearFWState: +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap diff --git a/autotest/units/001_one_port/059_firewall_tablearg/controlplane.conf b/autotest/units/001_one_port/059_firewall_tablearg/controlplane.conf new file mode 100644 index 00000000..ea6f2a23 --- /dev/null +++ b/autotest/units/001_one_port/059_firewall_tablearg/controlplane.conf @@ -0,0 +1,43 @@ +{ + "modules": { + "lp.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall.conf.txt", + "nextModules": [ + "route0" + ] + }, + "route0": { + "type": "route", + "vrf": "default", + "interfaces": { + "kni0.100": { + "ipv4Prefix": "200.0.10.2/24", + "neighborIPv4Address": "200.0.10.1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/059_firewall_tablearg/firewall.conf.txt b/autotest/units/001_one_port/059_firewall_tablearg/firewall.conf.txt new file mode 100644 index 00000000..e8c2346d --- /dev/null +++ b/autotest/units/001_one_port/059_firewall_tablearg/firewall.conf.txt @@ -0,0 +1,39 @@ +:BEGIN +table _SKIPTO_DST_PREFIX_ add 213.180.192.0/19 :TUN64_SKP1 +table _SKIPTO_DST_PREFIX_ add 213.180.200.0/25 :TUN64_SKP2 +table _SKIPTO_DST_PREFIX_ add 213.180.207.112/28 :TUN64_SKP3 +table _SKIPTO_DST_PREFIX_ add 213.180.207.64/27 :TUN64_SKP4 +table _SKIPTO_DST_PREFIX_ add 77.88.56.64/26 :TUN64_SKP5 +table _SKIPTO_DST_PREFIX_ add 77.88.46.0/25 :TUN64_SKP2 + +add skipto tablearg ip from any to table(_SKIPTO_DST_PREFIX_) +add deny ip from any to any + +:TUN64_SKP1 +add deny tcp from any to any setup +add allow tcp from any to any +add deny log logamount 500 all from any to any + +:TUN64_SKP2 +add allow tcp from any to any http,https +add deny tcp from any to any setup +add allow tcp from any to any +add deny log logamount 500 all from any to any + +:TUN64_SKP3 +add allow tcp from any to any dst-port 1024-65535 +add allow udp from any to any dst-port 1024-65535 +add deny log logamount 500 all from any to any + +:TUN64_SKP4 +add allow udp from any 500,4500 to any +add allow esp from any to any +add deny tcp from any to any setup +add allow tcp from any to any +add deny log logamount 500 all from any to any + +:TUN64_SKP5 +add deny tcp from any to any setup +add allow udp from any src-port 53 to any dst-port 1025-65535 +add allow ip from any to any keep-state in +add deny log logamount 500 all from any to any diff --git a/autotest/units/001_one_port/059_firewall_tablearg/gen.py b/autotest/units/001_one_port/059_firewall_tablearg/gen.py new file mode 100755 index 00000000..90fa086a --- /dev/null +++ b/autotest/units/001_one_port/059_firewall_tablearg/gen.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * + + +def write_pcap(filename, *packetsList): + if len(packetsList) == 0: + PcapWriter(filename)._write_header(Ether()) + return + + PcapWriter(filename) + + for packets in packetsList: + if type(packets) == list: + for packet in packets: + packet.time = 0 + wrpcap(filename, [p for p in packet], append=True) + else: + packets.time = 0 + wrpcap(filename, [p for p in packets], append=True) + + +def ipv4_send(_src, _dst): + return Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(src=_src, dst=_dst, ttl=64) + +def ipv4_recv(_src, _dst): + return Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(src=_src, dst=_dst, ttl=63) + +write_pcap("001-send.pcap", + # :TUN64_SKP1 + ipv4_send("10.0.0.3", "213.180.192.1")/TCP(dport=443, sport=(1024,1030), flags="S"), # drop by rule 6 + ipv4_send("10.1.0.5", "213.180.223.1")/TCP(dport=80, sport=1024, flags="A"), # allow by rule 8 + # :TUN64_SKP2 + ipv4_send("10.1.1.1", "77.88.46.1")/UDP(dport=123, sport=1024), # drop by rule 18 + # :TUN64_SKP3 + ipv4_send("10.1.1.1", "213.180.207.65")/UDP(dport=(1024,1030), sport=4500), # allow by rule 26 + ipv4_send("10.0.0.3", "213.180.207.65")/TCP(dport=443, sport=1024, flags="S"), # drop by rule 30 + # :TUN64_SKP4 + ipv4_send("33.33.33.33", "213.180.207.113")/TCP(dport=8080, sport=1024, flags="R")) # allow by rule 20 + +write_pcap("001-expect.pcap", + ipv4_recv("10.1.0.5", "213.180.223.1")/TCP(dport=80, sport=1024, flags="A"), + ipv4_recv("10.1.1.1", "213.180.207.65")/UDP(dport=(1024,1030), sport=4500), + ipv4_recv("33.33.33.33", "213.180.207.113")/TCP(dport=8080, sport=1024, flags="R")) diff --git a/autotest/units/001_one_port/059_firewall_via_tablearg/001-expect.pcap b/autotest/units/001_one_port/059_firewall_via_tablearg/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..cab8522f2f94b9de3a938f58dca40881a1f02447 GIT binary patch literal 1100 zcmbW#FK@y?7{~G7(|>8|Er=ot(^<$>`?8Co}SQG2DSUap&V(qg26>E>R7HgmNQmg~kiz7QOi1h#f literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/059_firewall_via_tablearg/001-send.pcap b/autotest/units/001_one_port/059_firewall_via_tablearg/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..1f3fcfdf55c204b5044dc2e07052fab121ed1a10 GIT binary patch literal 1236 zcmbV~ElH}9Xj)B(l z)1#<7O#ok`Q3Rj|1D|*YnBAG(&L(n9w_=m$m~O---!WZ_O@U)th)tnmnu|@5W19V& zI{dg?n+no28S@%6*+HW}4uyP=9MFS#M68{6qD%le?U^=~yf zONdA#;Q~=0-v2bS*ZR%#oavF>@388(S?hOf^; 200.0.10.1" +- ipv4Update: "200.0.20.0/24 -> 200.0.20.1" +- ipv4Update: "200.0.30.0/24 -> 200.0.30.1" +- ipv4Update: "200.0.40.0/24 -> 200.0.40.1" +- clearFWState: +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap diff --git a/autotest/units/001_one_port/059_firewall_via_tablearg/controlplane.conf b/autotest/units/001_one_port/059_firewall_via_tablearg/controlplane.conf new file mode 100644 index 00000000..43ba25b3 --- /dev/null +++ b/autotest/units/001_one_port/059_firewall_via_tablearg/controlplane.conf @@ -0,0 +1,69 @@ +{ + "modules": { + "lp.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp.300": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "300", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp.400": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "400", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall.conf.txt", + "nextModules": [ + "route0" + ] + }, + "route0": { + "type": "route", + "vrf": "default", + "interfaces": { + "kni0.100": { + "ipv4Prefix": "200.0.10.2/24", + "neighborIPv4Address": "200.0.10.1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.20.2/24", + "neighborIPv4Address": "200.0.20.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp.200" + }, + "kni0.300": { + "ipv4Prefix": "200.0.30.2/24", + "neighborIPv4Address": "200.0.30.1", + "neighborMacAddress": "00:00:00:33:33:33", + "nextModule": "lp.300" + }, + "kni0.400": { + "ipv4Prefix": "200.0.40.2/24", + "neighborIPv4Address": "200.0.40.1", + "neighborMacAddress": "00:00:00:44:44:44", + "nextModule": "lp.400" + } + } + } + } +} diff --git a/autotest/units/001_one_port/059_firewall_via_tablearg/firewall.conf.txt b/autotest/units/001_one_port/059_firewall_via_tablearg/firewall.conf.txt new file mode 100644 index 00000000..76624d24 --- /dev/null +++ b/autotest/units/001_one_port/059_firewall_via_tablearg/firewall.conf.txt @@ -0,0 +1,24 @@ +:BEGIN +table _SKIPTO_EARLY_IN_ create type iface +table _SKIPTO_EARLY_IN_ add lp.100 :VLAN100 +table _SKIPTO_EARLY_IN_ add lp.200 :VLAN200 +table _SKIPTO_EARLY_IN_ add lp.300 :VLAN300 +table _SKIPTO_EARLY_IN_ add lp.400 :VLAN400 +add skipto tablearg ip from any to any via table(_SKIPTO_EARLY_IN_) in +add deny ip from any to any + +:VLAN100 +add allow udp from any to any 53 +add allow tcp from any to any 443 +add deny ip from any to any + +:VLAN200 +add allow icmp from any to any icmptypes 0,8 +add deny ip from any to any + +:VLAN300 +add allow ip from any to any + +:VLAN400 +add deny tcp from any to any setup +add allow ip from any to any diff --git a/autotest/units/001_one_port/059_firewall_via_tablearg/gen.py b/autotest/units/001_one_port/059_firewall_via_tablearg/gen.py new file mode 100755 index 00000000..a2eb89aa --- /dev/null +++ b/autotest/units/001_one_port/059_firewall_via_tablearg/gen.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * + + +def write_pcap(filename, *packetsList): + if len(packetsList) == 0: + PcapWriter(filename)._write_header(Ether()) + return + + PcapWriter(filename) + + for packets in packetsList: + if type(packets) == list: + for packet in packets: + packet.time = 0 + wrpcap(filename, [p for p in packet], append=True) + else: + packets.time = 0 + wrpcap(filename, [p for p in packets], append=True) + +def fill_ether(vlan) -> str: + if vlan == 100: + return "00:00:00:11:11:11" + if vlan == 200: + return "00:00:00:22:22:22" + if vlan == 300: + return "00:00:00:33:33:33" + if vlan == 400: + return "00:00:00:44:44:44" + + +def ipv4_send(_vlan, _src, _dst): + return Ether(dst="00:11:22:33:44:55", src=fill_ether(_vlan))/Dot1Q(vlan=_vlan)/IP(src=_src, dst=_dst, ttl=64) + +def ipv4_recv(_vlan, _src, _dst): + return Ether(dst=fill_ether(_vlan), src="00:11:22:33:44:55")/Dot1Q(vlan=_vlan)/IP(src=_src, dst=_dst, ttl=63) + +write_pcap("001-send.pcap", + ipv4_send(100, "10.0.0.3", "200.0.20.123")/TCP(dport=443, sport=(1024,1030), flags="S"), # allow by rule 8 + ipv4_send(200, "10.1.0.5", "200.0.40.123")/ICMP(type=8, code=0, id=1, seq=0x0001), # allow by rule 12 + ipv4_send(100, "10.0.0.5", "200.0.20.123")/ICMP(type=8, code=0, id=1, seq=0x0001), # drop by rule 10 + ipv4_send(300, "10.1.1.1", "200.0.10.123")/UDP(dport=123, sport=1024), # allow by rule 16 + ipv4_send(400, "10.0.0.3", "200.0.30.123")/TCP(dport=443, sport=1024, flags="S"), # drop by rule 18 + ipv4_send(400, "10.1.1.1", "200.0.30.123")/UDP(dport=(1024,1030), sport=4500)) # allow by rule 20 + +write_pcap("001-expect.pcap", + ipv4_recv(200, "10.0.0.3", "200.0.20.123")/TCP(dport=443, sport=(1024,1030), flags="S"), + ipv4_recv(400, "10.1.0.5", "200.0.40.123")/ICMP(type=8, code=0, id=1, seq=0x0001), + ipv4_recv(100, "10.1.1.1", "200.0.10.123")/UDP(dport=123, sport=1024), + ipv4_recv(300, "10.1.1.1", "200.0.30.123")/UDP(dport=(1024,1030), sport=4500)) diff --git a/autotest/units/001_one_port/059_rib/001-expect.pcap b/autotest/units/001_one_port/059_rib/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..66fdd62cd221e22de4d9d3add852c50e0304cffd GIT binary patch literal 336 zcmca|c+)~A1{MYw_+QV!zzE|2X*(zeQi6hl41!9=E}@MK3@19=8C(wjcV%GE04cX; zn=O=oFaI8p$;cqW5CAhEfJuR2-9Z=+uW8OuKM^DAQ2fHs^FcQ$8a$ Y(>7EQWg3dx_MN`Rcn_;-mw=`L0L2F~;{X5v literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/059_rib/001-send.pcap b/autotest/units/001_one_port/059_rib/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..4104e66cb4bf96dceb5f75e1707c72e3d47a6b4a GIT binary patch literal 320 zcmca|c+)~A1{MYw_+QV!zzE|2X)7pZ5L7aD2?cTl1qB-!7*aSGTp1WNKuR6hW(nor z%fAO?GBSuT1i&;0FexysI|$<< literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/059_rib/002-expect.pcap b/autotest/units/001_one_port/059_rib/002-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..79218ffaf10c9e8932253cdabd7fa14f10b69c33 GIT binary patch literal 336 zcmca|c+)~A1{MYw_+QV!zzE|2X*(zeQi6hl41!9=E}@MK3@19=8N3<)yD~6nfRx*_ z%@)ePmwyk)WMmLw2!I(7z@)&i?jVduylHy{?*Rce(=Hq!-LyHU^O^D)v6;4^igeTV PoxaC-536aHfTjTerrI%a literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/059_rib/002-send.pcap b/autotest/units/001_one_port/059_rib/002-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..4104e66cb4bf96dceb5f75e1707c72e3d47a6b4a GIT binary patch literal 320 zcmca|c+)~A1{MYw_+QV!zzE|2X)7pZ5L7aD2?cTl1qB-!7*aSGTp1WNKuR6hW(nor z%fAO?GBSuT1i&;0FexysI|$<< literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/059_rib/autotest.yaml b/autotest/units/001_one_port/059_rib/autotest.yaml new file mode 100644 index 00000000..3cd6ad80 --- /dev/null +++ b/autotest/units/001_one_port/059_rib/autotest.yaml @@ -0,0 +1,2265 @@ +steps: + +# default (see neighbor in controlplane.conf) +- cli: | + rib static insert default 0.0.0.0/0 200.0.0.1 + +################################################################################################################# +# 1 rib_insert new nexthop_stuff, new prefix, new peer-proto-table_name +################################################################################################################# +- echo: "1 rib_insert() test: new nexthop_stuff, new prefix, new \"peer-proto-table_name\" - START" + +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.1 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 192.168.0.1 + prefix: 1.0.0.0/24 + path_information: 192.168.0.1:10001 + labels: + - 1100 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +# checking whether prefix was indeed flushed +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- echo: "1 rib_insert() test: new nexthop_stuff, new prefix, new \"peer-proto-table_name\" - DONE" + +################################################################################################################# +# 2 rib_insert new nexthop_stuff, existing prefix, existing peer-proto-table_name +################################################################################################################# +- echo: "2 rib_insert() test: new nexthop_stuff, existing prefix, existing \"peer-proto-table_name\" - START" + +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.1 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 192.168.0.1 + prefix: 1.0.0.0/24 + path_information: 192.168.0.2:10001 # in old nexthop_t table path_info is in the key, while nexthop ip is not! there can't be two different nexthop ips for the same path_info + labels: + - 1100 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 1 2 false + default 10000 static :: 2 2 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.2:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +- echo: "2 rib_insert() test: new nexthop_stuff, existing prefix, existing \"peer-proto-table_name\" - DONE" + +################################################################################################################# +# 3 rib_insert new nexthop_stuff, existing prefix, new peer-proto-table_name +################################################################################################################# +- echo: "3 rib_insert() test: new nexthop_stuff, existing prefix, new \"peer-proto-table_name\" - START" + +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.2 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 192.168.0.1 + prefix: 1.0.0.0/24 + path_information: 192.168.0.3:10001 + labels: + - 1100 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 1 2 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.2:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +- echo: "3 rib_insert() test: new nexthop_stuff, existing prefix, new \"peer-proto-table_name\" - DONE" + +################################################################################################################# +# 4 rib_insert new nexthop_stuff, new prefix, existing peer-proto-table_name +################################################################################################################# +- echo: "4 rib_insert() test: new nexthop_stuff, new prefix, existing \"peer-proto-table_name\" - START" + +- cli_check: | + route tunnel get route0 2.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ------- ----- ---------------- ---- ---------- + +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.1 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 192.168.0.1 + prefix: 2.0.0.0/24 + path_information: 192.168.0.1:10001 + labels: + - 1100 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 2 3 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.2:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 2.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +- cli_check: | + route tunnel get route0 2.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- echo: "4 rib_insert() test: new nexthop_stuff, new prefix, existing \"peer-proto-table_name\" - DONE" + +################################################################################################################# +# 5 rib_insert existing nexthop_stuff, new prefix, new peer-proto-table_name +################################################################################################################# +- echo: "5 rib_insert() test: existing nexthop_stuff, new prefix, new \"peer-proto-table_name\" - START" + +- cli_check: | + route tunnel get route0 3.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ------- ----- ---------------- ---- ---------- + +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.3 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 192.168.0.1 + prefix: 3.0.0.0/24 + path_information: 192.168.0.3:10001 + labels: + - 1100 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 2 3 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.3 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.2:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 2.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.3 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +- cli_check: | + route tunnel get route0 3.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- echo: "5 rib_insert() test: existing nexthop_stuff, new prefix, new \"peer-proto-table_name\" - DONE" + +################################################################################################################# +# 6 rib_insert existing nexthop_stuff, existing prefix, new peer-proto-table_name +################################################################################################################# +- echo: "6 rib_insert() test: existing nexthop_stuff, existing prefix, new \"peer-proto-table_name\" - START" + +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.4 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 192.168.0.1 + prefix: 3.0.0.0/24 + path_information: 192.168.0.3:10001 + labels: + - 1100 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 2 3 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.3 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.4 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.2:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 2.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.3 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.4 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +- echo: "6 rib_insert() test: existing nexthop_stuff, existing prefix, new \"peer-proto-table_name\" - DONE" + +################################################################################################################# +# 7 rib_insert existing nexthop_stuff, new prefix, existing peer-proto-table_name +################################################################################################################# +- echo: "7 rib_insert() test: existing nexthop_stuff, new prefix, existing \"peer-proto-table_name\" - START" + +- cli_check: | + route tunnel get route0 4.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ------- ----- ---------------- ---- ---------- + +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.1 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 192.168.0.1 + prefix: 4.0.0.0/24 + path_information: 192.168.0.1:10001 + labels: + - 1100 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 3 4 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.3 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.4 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.2:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 2.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.3 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.4 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +- cli_check: | + route tunnel get route0 4.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- echo: "7 rib_insert() test: existing nexthop_stuff, new prefix, existing \"peer-proto-table_name\" - DONE" + +################################################################################################################# +# 8 rib_insert existing nexthop_stuff, existing prefix, existing peer-proto-table_name +################################################################################################################# +- echo: "8 rib_insert() test: existing nexthop_stuff, existing prefix, existing \"peer-proto-table_name\" - START" + +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.1 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 192.168.0.1 + prefix: 1.0.0.0/24 + path_information: 192.168.0.1:10001 + labels: + - 1100 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 3 4 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.3 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.4 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.2:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 2.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.3 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.4 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +- echo: "8 rib_insert() test: existing nexthop_stuff, existing prefix, existing \"peer-proto-table_name\" - DONE" + +################################################################################################################# +# 9 rib_insert existing nexthop_stuff, existing prefix, existing peer-proto-table_name - new vrf-priority +################################################################################################################# +- echo: "9 rib_insert() test: existing nexthop_stuff, existing prefix, existing \"peer-proto-table_name\" - new vrf_priority - START" + +- rib_insert: + attribute: + vrf: tluafed + priority: 5000 + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.1 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 192.168.0.1 + prefix: 1.0.0.0/24 + path_information: 192.168.0.1:10001 + labels: + - 1100 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 3 4 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.3 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.4 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + tluafed 5000 autotest 10.10.10.1 ipv4 mpls-vpn 1 1 false + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.2:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 2.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.3 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.4 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + tluafed 5000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + +- echo: "9 rib_insert() test: existing nexthop_stuff, existing prefix, existing \"peer-proto-table_name\" - new vrf_priority - DONE" + +################################################################################################################# +# 10 rib_remove prefix for unexisting vrf-priority +################################################################################################################# +- echo: "10 rib_remove() test: trying to remove prefix for unexisting vrf-priority - START" + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- rib_remove: + attribute: + vrf: unknown + priority: 10000 + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.1 + prefixes: + - prefix: 1.0.0.0/24 + path_information: 192.168.0.1:10001 + labels: + - 1100 + +# expected result: nothing changed since previous step +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 3 4 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.3 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.4 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + tluafed 5000 autotest 10.10.10.1 ipv4 mpls-vpn 1 1 false + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.2:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 2.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.3 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.4 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + tluafed 5000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- echo: "10 rib_remove() test: trying to remove prefix for unexisting vrf-priority - DONE" + +################################################################################################################# +# 11 rib_remove prefix for existing vrf-priority but unexisting protocol-peer-table_name +################################################################################################################# +- echo: "11 rib_remove() test: trying to remove prefix for existing vrf-priority but unexisting protocol-peer-table_name - START" + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- rib_remove: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 100.100.100.10 + prefixes: + - prefix: 1.0.0.0/24 + path_information: 192.168.0.1:10001 + labels: + - 1100 + +# expected result: nothing changed since previous step +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 3 4 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.3 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.4 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + tluafed 5000 autotest 10.10.10.1 ipv4 mpls-vpn 1 1 false + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.2:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 2.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.3 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.4 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + tluafed 5000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- echo: "11 rib_remove() test: trying to remove prefix for existing vrf-priority but unexisting protocol-peer-table_name - DONE" + +################################################################################################################# +# 12 rib_remove unexisting prefix +################################################################################################################# +- echo: "12 rib_remove() test: trying to remove unexisting prefix - START" + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- cli_check: | + route tunnel get route0 1.0.0.0/32 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ------- ----- ---------------- ---- ---------- + +- rib_remove: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.1 + prefixes: + - prefix: 1.0.0.0/32 + path_information: 192.168.0.1:10001 + labels: + - 1100 + +# expected result: nothing changed since previous step +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 3 4 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.3 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.4 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + tluafed 5000 autotest 10.10.10.1 ipv4 mpls-vpn 1 1 false + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.2:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 2.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.3 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.4 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + tluafed 5000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- cli_check: | + route tunnel get route0 1.0.0.0/32 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ------- ----- ---------------- ---- ---------- + +- echo: "12 rib_remove() test: trying to remove unexisting prefix - DONE" + +################################################################################################################# +# 13 rib_remove prefix which has multiple path_info related to it +################################################################################################################# +- echo: "13 rib_remove() test: trying to remove prefix which has multiple path_info related to it - START" + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- rib_remove: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.1 + prefixes: + - prefix: 1.0.0.0/24 + path_information: 192.168.0.2:10001 + labels: + - 1100 + +# expected result: +# one less path for peer 10.10.10.1 in rib summary, amount of prefixes remains the same +# line for path_info 192.168.0.2:10001 +# 'default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.2:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1' +# is removed from rib prefixes + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 3 3 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.3 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.4 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + tluafed 5000 autotest 10.10.10.1 ipv4 mpls-vpn 1 1 false + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 2.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.3 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.4 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + tluafed 5000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- echo: "13 rib_remove() test: trying to remove prefix which has multiple path_info related to it - DONE" + +################################################################################################################# +# 14 rib_remove prefix of peer, which has other prefixes +################################################################################################################# +- echo: "14 rib_remove() test: trying to remove prefix for peer, which has some other prefixes - START" + +- cli_check: | + route tunnel get route0 2.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- rib_remove: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.1 + prefixes: + - prefix: 2.0.0.0/24 + path_information: 192.168.0.1:10001 + labels: + - 1100 + +# expected result: +# one less path and one less prefix for peer 10.10.10.1 in rib summary - prefixes record remains +# line for prefix 2.0.0.0/24 +# 'default 10000 2.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0. 1100 0 incomplete 0 n/s 13238:1:1' +# is removed from rib prefixes + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 2 2 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.3 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.4 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + tluafed 5000 autotest 10.10.10.1 ipv4 mpls-vpn 1 1 false + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.3 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.4 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + tluafed 5000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + +- cli_check: | + route tunnel get route0 2.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ------- ----- ---------------- ---- ---------- + +- echo: "14 rib_remove() test: trying to remove prefix for peer, which has some other prefixes - DONE" + +################################################################################################################# +# 15 rib_remove the last (for this peer) prefix which has the last path_info related to it +################################################################################################################# +- echo: "15 rib_remove() test: trying to remove the last (for this peer) prefix which has the last path_info related to it - START" + +- cli_check: | + route tunnel get route0 3.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- rib_remove: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.4 + prefixes: + - prefix: 3.0.0.0/24 + path_information: 192.168.0.3:10001 + labels: + - 1100 + +# expected result: +# there was only one path and one prefix for peer 10.10.10.4 - its record in rib summary +# 'default 10000 autotest 10.10.10.4 ipv4 mpls-vpn 1 1 false' +# should disappear, +# line for peer 10.10.10.4 +# 'default 10000 3.0.0.0/24 autotest 10.10.10.4 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1' +# is removed from rib prefixes + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 2 2 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.3 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + tluafed 5000 autotest 10.10.10.1 ipv4 mpls-vpn 1 1 false + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.3 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + tluafed 5000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + +# this prefix is still known because of other peer +- cli_check: | + route tunnel get route0 3.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- echo: "15 rib_remove() test: trying to remove the last (for this peer) prefix which has the last path_info related to it - DONE" + +################################################################################################################# +# 16 rib_insert multiple prefixes insertion +################################################################################################################# +- echo: "16 rib_insert() test: multiple prefixes insertion - START" + +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.1 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 192.168.0.1 + prefix: 5.0.0.0/24 + path_information: 192.168.0.1:10001 + labels: + - 1100 + - nexthop: 192.168.0.2 + prefix: 5.0.0.0/24 + path_information: 192.168.0.2:10001 + labels: + - 1100 + - nexthop: 192.168.0.2 + prefix: 6.0.0.0/24 + path_information: 192.168.0.2:10001 + labels: + - 1100 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 4 5 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.3 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + tluafed 5000 autotest 10.10.10.1 ipv4 mpls-vpn 1 1 false + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.3 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 5.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 5.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.2:10001 192.168.0.2 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 6.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.2:10001 192.168.0.2 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + tluafed 5000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + +- cli_check: | + route tunnel get route0 5.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 50.00 + kni0 192.168.0.2 1100 kni0.200 50.00 + +- cli_check: | + route tunnel get route0 6.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.2 1100 kni0.200 100.00 + +- echo: "16 rib_insert() test: multiple prefixes insertion - DONE" + +################################################################################################################# +# 17 rib_remove multiple prefixes removal +################################################################################################################# +- echo: "17 rib_remove() test: multiple prefixes removal - START" + +- rib_remove: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.1 + prefixes: + - prefix: 5.0.0.0/24 + path_information: 192.168.0.1:10001 + labels: + - 1100 + - prefix: 5.0.0.0/24 + path_information: 192.168.0.2:10001 + labels: + - 1100 + - prefix: 6.0.0.0/24 + path_information: 192.168.0.2:10001 + labels: + - 1100 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 2 2 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.3 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + tluafed 5000 autotest 10.10.10.1 ipv4 mpls-vpn 1 1 false + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.3 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + tluafed 5000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + +- cli_check: | + route tunnel get route0 5.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ------- ----- ---------------- ---- ---------- + +- cli_check: | + route tunnel get route0 6.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ------- ----- ---------------- ---- ---------- + +- echo: "17 rib_remove() test: multiple prefixes removal - DONE" + +################################################################################################################# +# 18 rib_remove all parts of request exist separately, however the whole combination does not - no remove +################################################################################################################# +- echo: "18 rib_remove() test: all parts of request exist separately, however the whole combination does not - START" + +- cli_check: | + route tunnel get route0 3.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- cli_check: | + route tunnel get route0 4.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- rib_remove: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.2 + prefixes: + - prefix: 4.0.0.0/24 + path_information: 192.168.0.1:10001 + labels: + - 1100 + - table_name: ipv4 mpls-vpn + peer: 10.10.10.1 + prefixes: + - prefix: 3.0.0.0/24 + path_information: 192.168.0.1:10001 + labels: + - 1100 + - table_name: ipv4 mpls-vpn + peer: 10.10.10.1 + prefixes: + - prefix: 4.0.0.0/24 + path_information: 192.168.0.3:10001 + labels: + - 1100 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 2 2 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.3 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + tluafed 5000 autotest 10.10.10.1 ipv4 mpls-vpn 1 1 false + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.3 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + tluafed 5000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + +- cli_check: | + route tunnel get route0 3.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- cli_check: | + route tunnel get route0 4.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- echo: "18 rib_remove() test: all parts of request exist separately, however the whole combination does not - DONE" + +################################################################################################################# +# 19 rib_clear request contains only protocol +################################################################################################################# +- echo: "19 rib_clear() test: request contains only protocol - START" + +## add some prefixes for new protocol +- rib_insert: + attribute: + protocol: 2_b_rmvd + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.1 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 192.168.0.1 + prefix: 1.0.0.0/24 + path_information: 192.168.0.1:10001 + labels: + - 1100 + - nexthop: 192.168.0.1 + prefix: 5.0.0.0/24 + path_information: 192.168.0.1:10001 + labels: + - 1100 + - table_name: ipv4 mpls-vpn + peer: 10.10.10.3 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 192.168.0.1 + prefix: 3.0.0.0/24 + path_information: 192.168.0.1:10001 + labels: + - 1100 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 2_b_rmvd 10.10.10.1 ipv4 mpls-vpn 2 2 false + default 10000 2_b_rmvd 10.10.10.3 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 2 2 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.3 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + tluafed 5000 autotest 10.10.10.1 ipv4 mpls-vpn 1 1 false + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 2_b_rmvd 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 2_b_rmvd 10.10.10.3 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.3 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 5.0.0.0/24 2_b_rmvd 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + tluafed 5000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- cli_check: | + route tunnel get route0 3.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- cli_check: | + route tunnel get route0 5.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +## remove prefixes for new protocol +- rib_clear: + attribute: + protocol: 2_b_rmvd + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 2 2 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.3 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + tluafed 5000 autotest 10.10.10.1 ipv4 mpls-vpn 1 1 false + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.3 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + tluafed 5000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- cli_check: | + route tunnel get route0 3.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- cli_check: | + route tunnel get route0 5.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ------- ----- ---------------- ---- ---------- + +- echo: "19 rib_clear() test: request contains only protocol - DONE" + +################################################################################################################# +# 20 rib_clear request contains protocol, peer, vrf, priority +################################################################################################################# +- echo: "20 rib_clear() test: request contains protocol, peer, vrf, priority - START" + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- cli_check: | + route tunnel get route0 4.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- rib_clear: + attribute: + protocol: autotest + peer: 10.10.10.3 + vrf: default + priority: 10000 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 2 2 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + tluafed 5000 autotest 10.10.10.1 ipv4 mpls-vpn 1 1 false + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + tluafed 5000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- cli_check: | + route tunnel get route0 4.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- rib_clear: + attribute: + protocol: autotest + peer: 10.10.10.1 + vrf: tluafed + priority: 5000 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 2 2 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- cli_check: | + route tunnel get route0 4.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- echo: "20 rib_clear() test: request contains protocol, peer, vrf, priority - DONE" + +################################################################################################################# +# 21 rib_clear combination of protocol, peer, vrf, priority from request does not exist - nothing to clear +################################################################################################################# +- echo: "21 rib_clear() test: combination of protocol, peer, vrf, priority from request does not exist (though they exist separately) - nothing to clear - START" + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- cli_check: | + route tunnel get route0 4.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- rib_clear: + attribute: + protocol: static + peer: 10.10.10.1 + vrf: default + priority: 10000 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 2 2 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- cli_check: | + route tunnel get route0 4.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- echo: "21 rib_clear() test: combination of protocol, peer, vrf, priority from request does not exist (though they exist separately) - nothing to clear - DONE" + +################################################################################################################# +# 22 rib_clear - nothing to clear +################################################################################################################# +- echo: "22 rib_clear() test: protocol/peer/vrf/priority from request do not exist - nothing to clear - START" + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- cli_check: | + route tunnel get route0 4.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +# unexisting peer +- rib_clear: + attribute: + protocol: autotest + peer: 10.10.10.3 + vrf: default + priority: 10000 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 2 2 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- cli_check: | + route tunnel get route0 4.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +# unexisting protocol +- rib_clear: + attribute: + protocol: 2_b_rmvd + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 2 2 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- cli_check: | + route tunnel get route0 4.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +# unexisting vrf +- rib_clear: + attribute: + protocol: autotest + peer: 10.10.10.1 + vrf: tluafed + priority: 10000 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 2 2 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- cli_check: | + route tunnel get route0 4.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +# unexisting priority +- rib_clear: + attribute: + protocol: autotest + peer: 10.10.10.1 + vrf: default + priority: 99999 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 2 2 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 1 1 false + default 10000 static :: 2 2 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- cli_check: | + route tunnel get route0 4.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- ----------- ----- ---------------- ---- ---------- + kni0 192.168.0.1 1100 kni0.200 100.00 + +- echo: "22 rib_clear() test: protocol/peer/vrf/priority from request do not exist - nothing to clear - DONE" + +################################################################################################################# +# won't need it anymore, no more 'route tunnel' checks +- cli: | + rib static remove default 0.0.0.0/0 200.0.0.1 + +################################################################################################################# +# 23 rib_lookup existing prefix for existing vrf +################################################################################################################# +- echo: "23 rib_lookup() test: existing prefix for existing vrf - START" + +- cli_check: | + rib lookup default 4.0.0.0 + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + +- cli_check: | + rib lookup default 4.0.0.255 + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 4.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + +- cli_check: | + rib lookup default 1.0.0.1 + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + +- cli_check: | + rib lookup default 1.0.0.255 + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + +# this is treated as update, not another insert! path_info for this prefix, this vrf-priority and protocol-peer-table_name has alreadu been existing, only labels have changed +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.2 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 192.168.0.1 + prefix: 1.0.0.0/24 + path_information: 192.168.0.3:10001 + labels: + - 1200 + +- cli_check: | + rib lookup default 1.0.0.255 + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1200 0 incomplete 0 n/s 13238:1:1 + +# rollback previous update +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.2 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 192.168.0.1 + prefix: 1.0.0.0/24 + path_information: 192.168.0.3:10001 + labels: + - 1100 + +- cli_check: | + rib lookup default 1.0.0.255 + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + + +- echo: "23 rib_lookup() test: existing prefix for existing vrf - DONE" + +################################################################################################################# +# 24 rib_lookup unexisting prefix for existing vrf +################################################################################################################# +- echo: "24 rib_lookup() test: unexisting prefix for existing vrf - START" + +- cli_check: | + rib lookup default 4.0.1.0 + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + --- -------- ------ -------- ---- ---------- ---------------- ------- ------ ---------------- ------ ------ --- ----------- ----------------- + +- cli_check: | + rib lookup default 1.0.1.255 + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + --- -------- ------ -------- ---- ---------- ---------------- ------- ------ ---------------- ------ ------ --- ----------- ----------------- + +- echo: "24 rib_lookup() test: unexisting prefix for existing vrf - DONE" + +################################################################################################################# +# 25 rib_lookup unexisting vrf +################################################################################################################# +- echo: "25 rib_lookup() test: unexisting vrf - START" + +- cli_check: | + rib lookup tluafed 4.0.0.0 + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + --- -------- ------ -------- ---- ---------- ---------------- ------- ------ ---------------- ------ ------ --- ----------- ----------------- + +- cli_check: | + rib lookup tluafed 1.0.0.1 + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + --- -------- ------ -------- ---- ---------- ---------------- ------- ------ ---------------- ------ ------ --- ----------- ----------------- + +- echo: "25 rib_lookup() test: unexisting vrf - DONE" + +################################################################################################################# +# 26 rib_get unexisting prefix for existing vrf +################################################################################################################# +- echo: "26 rib_get() test: unexisting prefix for existing vrf - START" + +- cli_check: | + rib get default 4.0.0.0/32 + vrf priority protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + --- -------- -------- ---- ---------- ---------------- ------- ------ ---------------- ------ ------ --- ----------- ----------------- + +- cli_check: | + rib get default 1.0.0.0/8 + vrf priority protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + --- -------- -------- ---- ---------- ---------------- ------- ------ ---------------- ------ ------ --- ----------- ----------------- + +- echo: "26 rib_get() test: unexisting prefix for existing vrf - DONE" + +################################################################################################################# +# 27 rib_get unexisting vrf +################################################################################################################# +- echo: "27 rib_get() test: unexisting vrf - START" + +- cli_check: | + rib get tluafed 4.0.0.0/24 + vrf priority protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + --- -------- -------- ---- ---------- ---------------- ------- ------ ---------------- ------ ------ --- ----------- ----------------- + +- cli_check: | + rib get tluafed 1.0.0.0/24 + vrf priority protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + --- -------- -------- ---- ---------- ---------------- ------- ------ ---------------- ------ ------ --- ----------- ----------------- + +- echo: "27 rib_get() test: unexisting vrf - DONE" + +################################################################################################################# +# 28 rib_get existing prefix for existing vrf +################################################################################################################# +- echo: "28 rib_get() test: existing prefix for existing vrf - START" + +- cli_check: | + rib get default 4.0.0.0/24 + vrf priority protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + +- cli_check: | + rib get default 1.0.0.0/24 + vrf priority protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- -------- ---------- ------------- ----------------- ----------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 192.168.0.1:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 192.168.0.3:10001 192.168.0.1 1100 0 incomplete 0 n/s 13238:1:1 + +- echo: "28 rib_get() test: existing prefix for existing vrf - DONE" + +################################################################################################################# +# 29 rib_save/rib_load test +################################################################################################################# +- echo: "29 rib_save()/rib_load() test: rib tables are restored after they were saved to file, cleared and loaded from file - START" + +## remove ALL prefixes, we will fill tables from scratch +- rib_clear: + attribute: + protocol: autotest + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---- ---------- -------- ----- ---- + default 10000 static :: 1 1 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- --------- -------- ---- ---------- ---------------- ------- ------ ---------------- ------ ------ --- ----------- ----------------- + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +# trying to have as many combinations with the same nexthop_stuff_t as possible (different prefixes, different peers, different vrfs, different path_infos, ...) +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 11.11.11.1 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 5.5.5.5 + prefix: 1.0.0.0/24 + path_information: 5.5.5.5:5555 + labels: + - 1100 + +# same nexthop_stuff_t, different peer +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 22.22.22.2 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 5.5.5.5 + prefix: 1.0.0.0/24 + path_information: 5.5.5.5:5555 + labels: + - 1100 + +# same nexthop_stuff_t, different path_info +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 11.11.11.1 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 5.5.5.5 + prefix: 1.0.0.0/24 + path_information: 5.5.5.5:9999 + labels: + - 1100 + +# same nexthop_stuff_t, different prefix +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 11.11.11.1 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 5.5.5.5 + prefix: 2.0.0.0/24 + path_information: 5.5.5.5:5555 + labels: + - 1100 + +# same nexthop_stuff_t, different prefix, different path_info +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 11.11.11.1 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 5.5.5.5 + prefix: 2.0.0.0/24 + path_information: 5.5.5.5:9999 + labels: + - 1100 + +# same nexthop_stuff_t, different vrf +- rib_insert: + attribute: + vrf: tluafed + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 11.11.11.1 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 5.5.5.5 + prefix: 1.0.0.0/24 + path_information: 5.5.5.5:5555 + labels: + - 1100 + +# different nexthop_stuff_t (labels) +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 11.11.11.1 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 5.5.5.5 + prefix: 1.0.0.0/24 + path_information: 5.5.5.5:5555 + labels: + - 2200 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 11.11.11.1 ipv4 mpls-vpn 2 4 false + default 10000 autotest 22.22.22.2 ipv4 mpls-vpn 1 1 false + default 10000 static :: 1 1 true + tluafed 10000 autotest 11.11.11.1 ipv4 mpls-vpn 1 1 false + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ---------------- ------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 1.0.0.0/24 autotest 11.11.11.1 ipv4 mpls-vpn 5.5.5.5:5555 5.5.5.5 2200 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 11.11.11.1 ipv4 mpls-vpn 5.5.5.5:9999 5.5.5.5 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 22.22.22.2 ipv4 mpls-vpn 5.5.5.5:5555 5.5.5.5 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 2.0.0.0/24 autotest 11.11.11.1 ipv4 mpls-vpn 5.5.5.5:5555 5.5.5.5 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 2.0.0.0/24 autotest 11.11.11.1 ipv4 mpls-vpn 5.5.5.5:9999 5.5.5.5 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + tluafed 10000 1.0.0.0/24 autotest 11.11.11.1 ipv4 mpls-vpn 5.5.5.5:5555 5.5.5.5 1100 0 incomplete 0 n/s 13238:1:1 + +# rib_save() +- cli: + dontdoit podumoi controlplane rib save > rib_saved.dmp + +## remove ALL prefixes, we will load rib tables from rib_saved.dmp +- rib_clear: + attribute: + protocol: autotest + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---- ---------- -------- ----- ---- + default 10000 static :: 1 1 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- --------- -------- ---- ---------- ---------------- ------- ------ ---------------- ------ ------ --- ----------- ----------------- + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +# rib_load() +- cli: + dontdoit podumoi controlplane rib load < rib_saved.dmp + +# loaded tables are the same as those we had saved +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 11.11.11.1 ipv4 mpls-vpn 2 4 false + default 10000 autotest 22.22.22.2 ipv4 mpls-vpn 1 1 false + default 10000 static :: 1 1 true + tluafed 10000 autotest 11.11.11.1 ipv4 mpls-vpn 1 1 false + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ---------------- ------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 1.0.0.0/24 autotest 11.11.11.1 ipv4 mpls-vpn 5.5.5.5:5555 5.5.5.5 2200 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 11.11.11.1 ipv4 mpls-vpn 5.5.5.5:9999 5.5.5.5 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 22.22.22.2 ipv4 mpls-vpn 5.5.5.5:5555 5.5.5.5 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 2.0.0.0/24 autotest 11.11.11.1 ipv4 mpls-vpn 5.5.5.5:5555 5.5.5.5 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 2.0.0.0/24 autotest 11.11.11.1 ipv4 mpls-vpn 5.5.5.5:9999 5.5.5.5 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + tluafed 10000 1.0.0.0/24 autotest 11.11.11.1 ipv4 mpls-vpn 5.5.5.5:5555 5.5.5.5 1100 0 incomplete 0 n/s 13238:1:1 + +- echo: "29 rib_save()/rib_load() test: rib tables are restored after they were saved to file, cleared and loaded from file - DONE" + +################################################################################################################# +# 30 rib_insert() -> rib_save() -> rib_clear() -> rib_insert() SOME OTHER_PREFIXES!! -> rib_load() - only loaded prefixes are present +################################################################################################################# +- echo: "30 rib_insert() -> rib_save() -> rib_clear() -> rib_insert() SOME OTHER_PREFIXES!! -> rib_load() - only loaded prefixes are present - START" + +## remove ALL prefixes, we will fill tables from scratch +- rib_clear: + attribute: + protocol: autotest + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---- ---------- -------- ----- ---- + default 10000 static :: 1 1 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- --------- -------- ---- ---------- ---------------- ------- ------ ---------------- ------ ------ --- ----------- ----------------- + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 11.11.11.1 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 5.5.5.5 + prefix: 1.0.0.0/24 + path_information: 5.5.5.5:5555 + labels: + - 1100 + +# same nexthop_stuff_t, different peer +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 22.22.22.2 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 5.5.5.5 + prefix: 1.0.0.0/24 + path_information: 5.5.5.5:5555 + labels: + - 1100 + +# same nexthop_stuff_t, different prefix +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 11.11.11.1 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 5.5.5.5 + prefix: 2.0.0.0/24 + path_information: 5.5.5.5:5555 + labels: + - 1100 + +# different path_info and nexthop_stuff_t +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 11.11.11.1 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 6.6.6.6 + prefix: 1.0.0.0/24 + path_information: 6.6.6.6:6666 + labels: + - 1100 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 11.11.11.1 ipv4 mpls-vpn 2 3 false + default 10000 autotest 22.22.22.2 ipv4 mpls-vpn 1 1 false + default 10000 static :: 1 1 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ---------------- ------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 1.0.0.0/24 autotest 11.11.11.1 ipv4 mpls-vpn 5.5.5.5:5555 5.5.5.5 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 11.11.11.1 ipv4 mpls-vpn 6.6.6.6:6666 6.6.6.6 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 22.22.22.2 ipv4 mpls-vpn 5.5.5.5:5555 5.5.5.5 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 2.0.0.0/24 autotest 11.11.11.1 ipv4 mpls-vpn 5.5.5.5:5555 5.5.5.5 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +# rib_save() +- cli: + dontdoit podumoi controlplane rib save > rib_saved.dmp + +## remove ALL prefixes +- rib_clear: + attribute: + protocol: autotest + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---- ---------- -------- ----- ---- + default 10000 static :: 1 1 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- --------- -------- ---- ---------- ---------------- ------- ------ ---------------- ------ ------ --- ----------- ----------------- + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +# insert different prefixes for different peers and vrfs - all will be rewritten after rib_load() +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 33.33.33.33 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 8.8.8.8 + prefix: 7.7.7.7/24 + path_information: 8.8.8.8:8888 + labels: + - 1100 + +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 33.33.33.33 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 8.8.8.8 + prefix: 9.9.9.9/24 + path_information: 8.8.8.8:8888 + labels: + - 1100 + +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 44.44.44.44 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 8.8.8.8 + prefix: 7.7.7.7/24 + path_information: 8.8.8.8:8888 + labels: + - 1100 + +- rib_insert: + attribute: + protocol: autotest + vrf: tluafed + tables: + - table_name: ipv4 mpls-vpn + peer: 33.33.33.33 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 8.8.8.8 + prefix: 7.7.7.7/24 + path_information: 8.8.8.8:8888 + labels: + - 1100 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ----------- ------------- -------- ----- ----- + default 10000 autotest 33.33.33.33 ipv4 mpls-vpn 2 2 false + default 10000 autotest 44.44.44.44 ipv4 mpls-vpn 1 1 false + default 10000 static :: 1 1 true + tluafed 10000 autotest 33.33.33.33 ipv4 mpls-vpn 1 1 false + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ----------- ------------- ---------------- ------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 7.7.7.7/24 autotest 33.33.33.33 ipv4 mpls-vpn 8.8.8.8:8888 8.8.8.8 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 7.7.7.7/24 autotest 44.44.44.44 ipv4 mpls-vpn 8.8.8.8:8888 8.8.8.8 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 9.9.9.9/24 autotest 33.33.33.33 ipv4 mpls-vpn 8.8.8.8:8888 8.8.8.8 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + tluafed 10000 7.7.7.7/24 autotest 33.33.33.33 ipv4 mpls-vpn 8.8.8.8:8888 8.8.8.8 1100 0 incomplete 0 n/s 13238:1:1 + +# rib_load() +- cli: + dontdoit podumoi controlplane rib load < rib_saved.dmp + +# loaded tables are the same as those we had saved +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 11.11.11.1 ipv4 mpls-vpn 2 3 false + default 10000 autotest 22.22.22.2 ipv4 mpls-vpn 1 1 false + default 10000 static :: 1 1 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ---------------- ------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 1.0.0.0/24 autotest 11.11.11.1 ipv4 mpls-vpn 5.5.5.5:5555 5.5.5.5 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 11.11.11.1 ipv4 mpls-vpn 6.6.6.6:6666 6.6.6.6 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 22.22.22.2 ipv4 mpls-vpn 5.5.5.5:5555 5.5.5.5 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 2.0.0.0/24 autotest 11.11.11.1 ipv4 mpls-vpn 5.5.5.5:5555 5.5.5.5 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +#TODO: would be interesting to check what was in prefixes_rebuild table on every step of tests with rib_save()/rib_load() + +- echo: "30 rib_insert() -> rib_save() -> rib_clear() -> rib_insert() SOME OTHER_PREFIXES!! -> rib_load() - only loaded prefixes are present - DONE" + +################################################################################################################# +# 31 fib rebuild +################################################################################################################# +- echo: "31 fib rebuild - START" + +## remove ALL prefixes, we will fill tables from scratch +- rib_clear: + attribute: + protocol: autotest + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---- ---------- -------- ----- ---- + default 10000 static :: 1 1 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- --------- -------- ---- ---------- ---------------- ------- ------ ---------------- ------ ------ --- ----------- ----------------- + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +# default (see neighbor in controlplane.conf) +- cli: | + rib static insert default 0.0.0.0/0 200.0.0.1 + +# original prefix with local_pref = 100 +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls + peer: 10.10.10.1 + med: 0 + large_communities: + - 13238:1:1 + local_pref: 100 + prefixes: + - nexthop: 200.0.0.1 + prefix: 1.0.0.0/24 + path_information: 200.0.0.1:10001 + labels: + - 1100 + +- echo: "insert prefix 1.0.0.0/24 from peer 10.10.10.1 with local_pref 100" + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ---------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls 1 1 false + default 10000 static :: 2 2 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ---------- ---------------- --------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls 200.0.0.1:10001 200.0.0.1 1100 100 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- --------- ----- ---------------- ---- ---------- + kni0 200.0.0.1 1100 kni0.200 100.00 + +# same prefix, different peer, different label but same med +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls + peer: 20.20.20.1 + med: 0 + large_communities: + - 13238:1:1 + local_pref: 100 + prefixes: + - nexthop: 200.0.0.1 + prefix: 1.0.0.0/24 + path_information: 200.0.0.1:10001 + labels: + - 1200 + +- echo: "insert same prefix 1.0.0.0/24 from another peer 20.20.20.1 with local_pref 100" + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ---------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls 1 1 false + default 10000 autotest 20.20.20.1 ipv4 mpls 1 1 false + default 10000 static :: 2 2 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ---------- ---------------- --------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls 200.0.0.1:10001 200.0.0.1 1100 100 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 20.20.20.1 ipv4 mpls 200.0.0.1:10001 200.0.0.1 1200 100 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- --------- ----- ---------------- ---- ---------- + kni0 200.0.0.1 1100 kni0.200 50.00 + kni0 200.0.0.1 1200 kni0.200 50.00 + +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap + +# original prefix, but local_pref was changed +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls + peer: 10.10.10.1 + med: 0 + large_communities: + - 13238:1:1 + local_pref: 10 + prefixes: + - nexthop: 200.0.0.1 + prefix: 1.0.0.0/24 + path_information: 200.0.0.1:10001 + labels: + - 1100 + +- echo: "update prefix 1.0.0.0/24 from peer 10.10.10.1 with new local_pref 10 (this route (with label 1100)) must be gone from fib)" + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ---------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls 1 1 false + default 10000 autotest 20.20.20.1 ipv4 mpls 1 1 false + default 10000 static :: 2 2 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ---------- ---------------- --------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.0.1 200.0.0.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls 200.0.0.1:10001 200.0.0.1 1100 10 incomplete 0 n/s 13238:1:1 + default 10000 1.0.0.0/24 autotest 20.20.20.1 ipv4 mpls 200.0.0.1:10001 200.0.0.1 1200 100 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +# only one route should survive in fib +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- --------- ----- ---------------- ---- ---------- + kni0 200.0.0.1 1200 kni0.200 100.00 + +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap + +# without manual interference, this one messes with the next autottest +- cli: | + rib static remove default 0.0.0.0/0 200.0.0.1 + +- echo: "31 fib rebuild - DONE" \ No newline at end of file diff --git a/autotest/units/001_one_port/059_rib/controlplane.conf b/autotest/units/001_one_port/059_rib/controlplane.conf new file mode 100644 index 00000000..8d8bbb1c --- /dev/null +++ b/autotest/units/001_one_port/059_rib/controlplane.conf @@ -0,0 +1,32 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "route0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "route0" + }, + "route0": { + "type": "route", + "interfaces": { + "kni0.100": { + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.0/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/059_rib/gen.py b/autotest/units/001_one_port/059_rib/gen.py new file mode 100644 index 00000000..42917bfd --- /dev/null +++ b/autotest/units/001_one_port/059_rib/gen.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * +from scapy.contrib.mpls import MPLS + + +def write_pcap(filename, *packetsList): + if len(packetsList) == 0: + PcapWriter(filename)._write_header(Ether()) + return + + PcapWriter(filename) + + for packets in packetsList: + if type(packets) == list: + for packet in packets: + packet.time = 0 + wrpcap(filename, [p for p in packet], append=True) + else: + packets.time = 0 + wrpcap(filename, [p for p in packets], append=True) + +# two routes with same local preference - equal possibility to be sent with either label +write_pcap("001-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="1.0.0.1", src="111.222.111.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="1.0.0.1", src="222.222.222.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="1.0.0.1", src="111.2.111.1", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="1.0.0.1", src="222.1.222.1", ttl=64)/TCP()) + +write_pcap("001-expect.pcap", + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="111.222.111.222", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="111.2.111.1", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.1", src="222.1.222.1", ttl=63)/TCP()) + +# only one best route left in fib - always label 1200 +write_pcap("002-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="1.0.0.1", src="111.222.111.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="1.0.0.1", src="222.222.222.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="1.0.0.1", src="111.2.111.1", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="1.0.0.1", src="222.1.222.1", ttl=64)/TCP()) + +write_pcap("002-expect.pcap", + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.1", src="111.222.111.222", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.1", src="111.2.111.1", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.1", src="222.1.222.1", ttl=63)/TCP()) diff --git a/autotest/units/001_one_port/060_firewall_inplace_rules/001-expect.pcap b/autotest/units/001_one_port/060_firewall_inplace_rules/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..ba2dd468d2d61b26bf80f5563210b34912f7e1d1 GIT binary patch literal 2606 zcmca|c+)~A1{MYw_+QV!zzE|2X)7oOQc6ln41!9=E}@MK3@11kTp1WNKuYb|(ob+P zFfao#E6|((nC1W`1%~o&7>{I=7|~4XBHJV;G?O~XHi;R{qz(M)P1 z+axwLlUflbsR82|gn(NKc~BGI9i01UO<(NIGTwO7F417RS*DAyQn0Bg4f zd$#D#;S_2R&oVGL0U00+1cHKs@OnL^?QQ}{j6={~0Yt+9BLlaP35)}#L3O<;1INh} vm?#xYWCWX-Ohpr!z$PY9(L`pjiHTG+kp*mG0u@bU1)CU8MHAV;CdL5(^fLTc literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/060_firewall_inplace_rules/001-send.pcap b/autotest/units/001_one_port/060_firewall_inplace_rules/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..d8bd4e1c3096cd1650ebcacb160bd256fad8b5ac GIT binary patch literal 2848 zcmca|c+)~A1{MYw_+QV!zzE|2X)7pZ5L7aD2?cVLl$0777*aSGTp1WNKuR6h(oS$O zFfao#E6|((nC1W`1%~o&7>{I=7|~4XBHJV;G?O~XHi;R{qz(M)P1 z+axwLlUhkLDS8JNBLk}_1A`EHD#)oun4|_wF(8aBJu!+fFe(7klhs*JTEb@1MN 10.0.0.1" +- ipv6Update: "::/0 -> fe80::1" +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap diff --git a/autotest/units/001_one_port/060_firewall_inplace_rules/controlplane.conf b/autotest/units/001_one_port/060_firewall_inplace_rules/controlplane.conf new file mode 100644 index 00000000..e5cad0e9 --- /dev/null +++ b/autotest/units/001_one_port/060_firewall_inplace_rules/controlplane.conf @@ -0,0 +1,47 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": [ + ":BEGIN", + "add allow ip from any to { 10.0.0.5 or 1234::5 }", + "add allow ip from { 10.0.0.5 or 1234::5 } to any", + "add deny ip from any to any" + ], + "nextModules": [ + "vrf0" + ] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv6Prefix": "1234::5/64", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "10.0.0.5/24", + "neighborIPv4Address": "10.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/060_firewall_inplace_rules/gen.py b/autotest/units/001_one_port/060_firewall_inplace_rules/gen.py new file mode 100755 index 00000000..cd842236 --- /dev/null +++ b/autotest/units/001_one_port/060_firewall_inplace_rules/gen.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * +from scapy.contrib.mpls import MPLS + + +def write_pcap(filename, *packetsList): + if len(packetsList) == 0: + PcapWriter(filename)._write_header(Ether()) + return + + PcapWriter(filename) + + for packets in packetsList: + if type(packets) == list: + for packet in packets: + packet.time = 0 + wrpcap(filename, [p for p in packet], append=True) + else: + packets.time = 0 + wrpcap(filename, [p for p in packets], append=True) + +def ipv4_send(_src, _dst): + return Ether(dst="00:11:22:33:44:55", src="00:00:00:22:22:22")/Dot1Q(vlan=100)/IP(src=_src, dst=_dst, ttl=64) + +def ipv4_recv(_src, _dst): + return Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(src=_src, dst=_dst, ttl=63) + +def ipv6_send(_src, _dst): + return Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=200)/IPv6(src=_src, dst=_dst, hlim=64, fl=0) + +def ipv6_recv(_src, _dst): + return Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(src=_src, dst=_dst, hlim=63, fl=0) + +write_pcap("001-send.pcap", + ipv4_send("10.0.0.3", "10.0.0.5")/TCP(dport=80, sport=(1024,1030), flags="S"), + ipv4_send("10.1.0.5", "21.0.0.18")/TCP(dport=80, sport=1024, flags="S"), + fragment(ipv4_send("10.0.0.5", "21.0.0.18")/TCP(dport=80, sport=1024, flags="S")/("QQQ"*400), fragsize=256), + ipv6_send("2000::1:b", "1234::5")/UDP(dport=53, sport=(1024,1030)), + ipv6_send("2000::cafe", "2200::beef")/TCP(dport=443, sport=1024, flags="S"), + ipv4_send("33.33.33.33", "33.33.33.34")/TCP(flags="R")) + +write_pcap("001-expect.pcap", + ipv4_recv("10.0.0.3", "10.0.0.5")/TCP(dport=80, sport=(1024,1030), flags="S"), + fragment(ipv4_recv("10.0.0.5", "21.0.0.18")/TCP(dport=80, sport=1024, flags="S")/("QQQ"*400), fragsize=256), + ipv6_recv("2000::1:b", "1234::5")/UDP(dport=53, sport=(1024,1030))) diff --git a/autotest/units/001_one_port/061_nat64stateful/001-expect.pcap b/autotest/units/001_one_port/061_nat64stateful/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..0774458e148c721c908e5c32de52a75baef9bd1b GIT binary patch literal 690 zcmca|c+)~A1{MYw`2U}Qff2?5(pFFmq?DAD7zCA!T|yff7*237xH2$kfE3!ZRbQM5 z1ZhCP!N3pz5(9w%CIyD}$q+V(B-JFw-7vi%liI*`K}3i$=>pVE=@@RB1T&XNHzApX g<|cI#O&Sd+;!?qRXxwGUJIFi0!Wfha0uvb+0L4vcG5`Po literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/001-send.pcap b/autotest/units/001_one_port/061_nat64stateful/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..9500d69b876265144fe92ac0a12113b4edb4f202 GIT binary patch literal 870 zcmca|c+)~A1{MYw`2U}Qff2?5(tc3PAgE;Q5(<`JY-C_aX}g;M;)t+0tU?0}DgS4K z)d7h#AmCtN2!Qbem=qXN3t>F!n9jHxW**4&6gC)-3Z|!HxV?b7rlYx?m5Qd1hC4i6 aqNPY+tkN*tGvpoQ9boYYN|E~Z3=9Cn>b(R2 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/002-expect.pcap b/autotest/units/001_one_port/061_nat64stateful/002-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..df85c4983e50d91e147dbd7dd060580ae0127ec4 GIT binary patch literal 776 zcmca|c+)~A1{MYw`2U}Qff2?5(tc13qyz;883dJ#T|yff7*g8qCIE#PMA+;ZQvS~d zF+m^=2v(s1h5!zTB#;bXQea3egmbB2I^%9s(^J?eFg+d3>8nuOE(COY0yRxXaXX^| Z14V8hzTqwi4EIEug*z}-lfN=B000xCs}}$O literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/002-send.pcap b/autotest/units/001_one_port/061_nat64stateful/002-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..e6bd958e3da71e3c7a6ac0fb2853ec6ecf3d08be GIT binary patch literal 1208 zcmca|c+)~A1{MYw`2U}Qff2?5(pFH+AgE;Q5(<`JYGhzI!NK6lz@PzA>cCcYAq@y- z0s%t+2V8FelLABgWH^^ZlNfiSn$)I2qDkk0PD;mclMv8NP2`${;wDA~29n)0bizpx z7*5Sp2`6BPw~3Qz5>hyEx4`s*(o+jRj7Mt9WZaEvQqvL=O+uunK-84kK9O9L826x> w)TTzFNsFNQ?l?xiOC{GNlr#<{9 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/003-expect.pcap b/autotest/units/001_one_port/061_nat64stateful/003-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..2be06fdd6756cc97edea69a01aa7d3693b0e0906 GIT binary patch literal 394 zcmca|c+)~A1{MYw`2U}Qff2?5(pFFmq?DAD7zCA!T|yff7*237xH2+mfE3!ZRbQA1 z1ZhCP!N3pz5(9w%CIyD}$q+V(#A6Z@+@$jqn#2M(=`4jNHNZ^@q|l`QFq5h-;WG&U D1E4(@ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/003-send.pcap b/autotest/units/001_one_port/061_nat64stateful/003-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..6fef1705807263bbecdedba3ac86ca1f1a6f23d7 GIT binary patch literal 494 zcmca|c+)~A1{MYw`2U}Qff2?5(tc3PAgE;Q5(<`JY-C_aX}g;s0OX0VIjlkh3@QI- ugVh0vG$7z$U2v(s1h5!zjG(!NB0z+ycoQuzN1)wV0neISK(=&jE)6VVrAILWy0DQ%5pa1{> literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/004-send.pcap b/autotest/units/001_one_port/061_nat64stateful/004-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..882375b5757d2035633932a4324909b057614123 GIT binary patch literal 394 zcmca|c+)~A1{MYw`2U}Qff2?5(pFH+AgE;Q5(<`JYGhzI!NK6l$e;mI>cCcYJ`D(F x0s%t+2V8FelLABgWH=X}Nlb8)&QWL*3*4kL6q?ikHz|NZlm5d@s=SELBmjw?J0k!9 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/005-expect.pcap b/autotest/units/001_one_port/061_nat64stateful/005-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..677bc64dee6285b72f2382ceb7f260d6dcee2b0b GIT binary patch literal 98 zcmca|c+)~A1{MYw`2U}Qff2?5(pFFmq?DAD7zCA!T|yff7*237xH2$kfE3!ZRbQM5 X1ZhCP!N3pz5(9w%CIyD}$qWnt3po$? literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/005-send.pcap b/autotest/units/001_one_port/061_nat64stateful/005-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..4dd1595b18ed3cb108ffd931dc4a5a3af6ca5cac GIT binary patch literal 8580 zcmca|c+)~A1{MYw`2U}Qff2?5(!YRGAj}}BWb6_OmSAjTU`T1Zn*ijn9MExCg$5W> z{?7)h0}^RKzy>r>$RwKRgWZ4NS2}eu2(Gq{O)*G$)hgwSqRuVn~GC&x6n~-4*F>ON5 z0#Hdf6zX}HuPHD81(909TpY9AhFbg&h1ePm)6w3;XgZ}$?}3^nA*3Zdnp;P6>u7GJ zO>P~{TeQntu#)f=kO9ItTEYtmw}b^5AT8m+Iwk<~X&8_J!Z>^?L)fRlabSk_RA)u> zap2TKkg*Uzc^lgb*v4Lc_PtO8!{pmSChe)Cxqx=LV6djy(KsKC^P$?Rpk_(PvJ+Gi jj^>8Z+%Qyg!)V$axoHnpAwgR@XK_%f}ZLa_TznRU; literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/006-expect.pcap b/autotest/units/001_one_port/061_nat64stateful/006-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a324304509bdd12aef4a69458a409cefefafe614 GIT binary patch literal 24 Ycmca|c+)~A1{MYw`2U}Qff2|708wKE@Bjb+ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/006-send.pcap b/autotest/units/001_one_port/061_nat64stateful/006-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..e45d3e8b11a24194017c8f5d2df9465a8c62a679 GIT binary patch literal 8226 zcmca|c+)~A1{MYw`2U}Qff2?5()WN;Aj}}BWb6_OmSAdRU^v0S;L5;qM#w~g!GX>B zXBrU91OkQt4!GU`CIyD@Tm}Y5CubK|H+K(1BV!X&Gjj_|14E-xvC%LXO$VcSVX%}3 zutJMqX*V5M+9knCyU`MDv{WCh*+y&kq1Kv#m3F6q3=qcFwqw{KWWuQDz?OC&R@x1P z`Woglg5@}agP`*}n9o41RxXac8AB}|heC{uhUsWae>9!arln7GX*V5M+J(bPyU`pu znj=SZByDo!Xx^e--h!2O`+y7(#@cFK18%hnragd_c7wH#4)YBWEmcP6e=y&0FjzPU znY5>lrZd{5v%#8TM&o=m&WCEfO>}8D-GR|L9ah?nrufkmKU7ovXxbgQX%|-75z$g* NO#1*U?FMVR0{~s^O78#w literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/007-expect.pcap b/autotest/units/001_one_port/061_nat64stateful/007-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..c40e32960bc5c7cc2daaa719fa2e3feb25c85757 GIT binary patch literal 107 zcmca|c+)~A1{MYw`2U}Qff2?5(#}u}q?DAD7zCA!T|yff7*237xH2#pf)v^_R-c^- l1ZhCP!62I>WYV6RQmT-VSX`n|R+*Tbky@OSSeBWb0RRLv7#siq literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/007-send.pcap b/autotest/units/001_one_port/061_nat64stateful/007-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..9516fb49284d49642673b9ac4b28ebbc4d371e32 GIT binary patch literal 218 zcmca|c+)~A1{MYw`2U}Qff2?5(&13dAgE;Q5(<`JY-C_aX}g;M;>cP#tU?0}DgS4K z)d7h#AZTD{`Xpr1o|;mskdatiqEJ?un4FPXoRe6VnVbPr=nZ6mFb-=330u?1aAR^< Qg|lK=W=UdBWuk%+07kPs)c^nh literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/008-expect.pcap b/autotest/units/001_one_port/061_nat64stateful/008-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..fb688a13505cf1ca3eefd04a34a36b98c71c189a GIT binary patch literal 127 zcmca|c+)~A1{MYw`2U}Qff2?5(&11Hqyz;883dJ#T|yff7*g8qCIE#PWUcHOQvS~d pF+m^=2v(tiMux^uLMH90DWwV-iNz%fWtEA^8L7oNiDj9|834q7Bb@*M literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/008-send.pcap b/autotest/units/001_one_port/061_nat64stateful/008-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a5e3c865bf1196b5aa7061a37e900b7ca4c4dcea GIT binary patch literal 427 zcmca|c+)~A1{MYw`2U}Qff2?5(#}xKAgE;Q5(<`JYGhzI!NK6lz+ebc>cCiaCJhK? z0s#YqYL1XedumFlLPlb7i9%UrVsb`maZX}cW^xA1R8o!HVAY;V4I{IGjyz6XSI&ca o{5Vk_HwT6Q2xARPRcKh=fQ2OoLkVM8g|lK=W=UdBWuk%+0Kvyz!~g&Q literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/009-expect.pcap b/autotest/units/001_one_port/061_nat64stateful/009-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a324304509bdd12aef4a69458a409cefefafe614 GIT binary patch literal 24 Ycmca|c+)~A1{MYw`2U}Qff2|708wKE@Bjb+ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/009-send.pcap b/autotest/units/001_one_port/061_nat64stateful/009-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..c33208e0930b1d6c83ac5a4f5b891eb02f7e3e58 GIT binary patch literal 738 zcmca|c+)~A1{MYw`2U}Qff2?5(pFH+AgE;Q5(<`JY-C_aX}g;M=14oNLIVsb|7U}x zfJ7P)z}N&#Vx*c$)x?|R1auq-YGcY0o4{9176B(#(A|usJWT(1`oYXdv IQHOXF0k)g3tpET3 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/010-expect.pcap b/autotest/units/001_one_port/061_nat64stateful/010-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..c24c22836ec446bd32010a0b31fdb3f131792a9a GIT binary patch literal 306 zcmca|c+)~A1{MYw`2U}Qff2?5(tc13qyz;883dJ#T|yff7*g8qCIE#PMA+;ZQvS~d dF+m^=2v(s1h5!zTB#;bXQea3egmZ_a=>X8dLf-%Y literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/010-send.pcap b/autotest/units/001_one_port/061_nat64stateful/010-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..9336fabb85ce4c35e52da98af95b575dc58c66d7 GIT binary patch literal 2682 zcmca|c+)~A1{MYw`2U}Qff2?5(pFH+AgE;Q5(<`JYGhzI!NK6lz@PzA>cCcYAq@y- z0s%t+2V8FelLABgWH=YUNnlHXCjG!^(sCkAVuZTsJH;jmLrr>0u}Pv(lOE$VX&G_8 zW7L6|RCxxMNp1ZIll*{85XOu(F1RKqpFS2-0880;&>!BRG~T618=IQsvn`b*kdK#{0MC)c;KyT usOm>(S>myrZho|emH<=fW}_|C#>o`hh*XB+D*<3-sQVI1ZEV}lzyJUO=_^41 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/011-expect.pcap b/autotest/units/001_one_port/061_nat64stateful/011-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a324304509bdd12aef4a69458a409cefefafe614 GIT binary patch literal 24 Ycmca|c+)~A1{MYw`2U}Qff2|708wKE@Bjb+ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/011-send.pcap b/autotest/units/001_one_port/061_nat64stateful/011-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..9587cbab0f50095c5df9dad51fa21bd693f090da GIT binary patch literal 1016 zcmca|c+)~A1{MYw`2U}Qff2?5(t1$LAgE;Q5(<`JYGhzI!NK6lz#s!s>L6HkF%1Z2 z0s%t+2Ll7g_db{br0Hhd4buHhnIzp8fL5m?+1*Q?Zm8W#BSo-{!0}BPqL)bB7om2iL+$P*S2x&hC6aUxBYy(`q#;~% literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/012-send.pcap b/autotest/units/001_one_port/061_nat64stateful/012-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..e97e7713710c37865cdf8324462c78539386fbb2 GIT binary patch literal 680 zcmca|c+)~A1{MYw`2U}Qff2?5(oRs!AgE;Q5(<`JY-C_aX}g;M;&2E$tU?0}DgS4K z)d7h#AmCtN2w>p2ngbJ~hKY>3891)Mok_8Y=}L6HkF%1Z2 z0s%t+2Ll7g_db{br0Hhd4buHhnIzp8fL5m?+1*Q?Zm8W#BGBG(LwKylSEHgO+0FYXRQ~&?~ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/014-send.pcap b/autotest/units/001_one_port/061_nat64stateful/014-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..3edf4e23787fd6850e979d18e078a927bd4f419b GIT binary patch literal 973 zcmca|c+)~A1{MYw`2U}Qff2?5(tc3PAgE;Q5(<`JY-C_aX}g;M;)t+0tU>|1cQd5? zpAA+AB+`I@gMlFc#t&dpUPX!>Zl zL(?TjiUh_g4Z}S{-a+007LTA5DW?bHF))M!nIMcKH_2KN%uNjp1^a|dIyzEH6*3Zw TOBBi~6O%Jii*pjoGLtg^UANzS literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/015-expect.pcap b/autotest/units/001_one_port/061_nat64stateful/015-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..9674015b60c7541cf0172600bcbe96d42eade6a2 GIT binary patch literal 973 zcmca|c+)~A1{MYw`2U}Qff2?5(tc13qyz;883dJ#T|yff7*g8qCIE#PMA+;ZQvS~d zF+m^=2v(th-MbkAI3SWhGJr{eAtV9LrGn{cCcYAq@y- z0s%vS_%@j4044>7^1Cn|sU|V*Mm4Fdh(wdl1D%wP;U*!Vo6eAH5{jD`6&Of%)6fYg zL0~wYrAjyfL%b}JM3c?|<1Pafck&K;-(Y${>B(_5jK{#>3}k{Z)|6=oPMM5VXW%K5 gL1ePxtB#J8QiY7f;u3|j%EaW1)Z(1PvdrWR0Gp11YybcN literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/061_nat64stateful/autotest.yaml b/autotest/units/001_one_port/061_nat64stateful/autotest.yaml new file mode 100644 index 00000000..23e87935 --- /dev/null +++ b/autotest/units/001_one_port/061_nat64stateful/autotest.yaml @@ -0,0 +1,117 @@ +steps: +- ipv4Update: "0.0.0.0/0 -> 200.0.0.1" +- ipv6Update: "::/0 -> fe80::1" +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap +- sendPackets: + - port: kni0 + send: 003-send.pcap + expect: 003-expect.pcap +- sendPackets: + - port: kni0 + send: 004-send.pcap + expect: 004-expect.pcap +- sendPackets: + - port: kni0 + send: 005-send.pcap + expect: 005-expect.pcap +- sendPackets: + - port: kni0 + send: 006-send.pcap + expect: 006-expect.pcap +- sendPackets: + - port: kni0 + send: 007-send.pcap + expect: 007-expect.pcap +- sendPackets: + - port: kni0 + send: 008-send.pcap + expect: 008-expect.pcap +- sendPackets: + - port: kni0 + send: 009-send.pcap + expect: 009-expect.pcap +- sendPackets: + - port: kni0 + send: 010-send.pcap + expect: 010-expect.pcap +- sendPackets: + - port: kni0 + send: 011-send.pcap + expect: 011-expect.pcap +- sendPackets: + - port: kni0 + send: 012-send.pcap + expect: 012-expect.pcap +- sendPackets: + - port: kni0 + send: 013-send.pcap + expect: 013-expect.pcap +- cli_check: | + YANET_FORMAT_COLUMNS=module,ipv6_source,ipv4_source,ipv4_destination,proto,origin_port_source,port_source,port_destination,lan_flags,wan_flags nat64stateful state + module ipv6_source ipv4_source ipv4_destination proto origin_port_source port_source port_destination lan_flags wan_flags + ------ --------------------------------------- --------------- ---------------- ------ ------------------ ----------- ---------------- --------- ----------- + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.103 udp 2048 2048 80 + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.102 icmpv6 4660 4660 0 + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.102 tcp 2048 2048 80 syn syn + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.103 tcp 2048 2048 80 syn syn,ack,fin + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.102 udp 2048 2048 80 + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.103 udp 2048 2048 443 + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.104 tcp 8000 8000 8000 syn + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.102 tcp 2048 2048 443 syn syn + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.103 tcp 2048 2048 443 syn syn,ack + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.102 udp 2048 2048 443 +- sendPackets: + - port: kni0 + send: 014-send.pcap + expect: 014-expect.pcap +- cli_check: | + YANET_FORMAT_COLUMNS=module,ipv6_source,ipv4_source,ipv4_destination,proto,origin_port_source,port_source,port_destination,lan_flags,wan_flags nat64stateful state + module ipv6_source ipv4_source ipv4_destination proto origin_port_source port_source port_destination lan_flags wan_flags + ------ --------------------------------------- --------------- ---------------- ------ ------------------ ----------- ---------------- --------- ----------- + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.103 udp 2048 2048 80 + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.102 icmpv6 4660 4660 0 + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.102 tcp 2048 2048 80 syn syn + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb 153.153.153.153 102.102.102.103 tcp 2048 6070 443 syn + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb 153.153.153.153 102.102.102.102 icmpv6 4660 8682 0 + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.103 tcp 2048 2048 80 syn syn,ack,fin + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb 153.153.153.153 102.102.102.102 tcp 2048 6070 443 syn + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb 153.153.153.153 102.102.102.104 tcp 8000 12022 8000 syn + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.102 udp 2048 2048 80 + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.103 udp 2048 2048 443 + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.104 tcp 8000 8000 8000 syn + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb 153.153.153.153 102.102.102.103 tcp 2048 6070 80 syn + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.102 tcp 2048 2048 443 syn syn + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb 153.153.153.153 102.102.102.102 tcp 2048 6070 80 syn + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.103 tcp 2048 2048 443 syn syn,ack + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.102 udp 2048 2048 443 +- sendPackets: + - port: kni0 + send: 015-send.pcap + expect: 015-expect.pcap +- cli_check: | + YANET_FORMAT_COLUMNS=module,ipv6_source,ipv4_source,ipv4_destination,proto,origin_port_source,port_source,port_destination,lan_flags,wan_flags nat64stateful state + module ipv6_source ipv4_source ipv4_destination proto origin_port_source port_source port_destination lan_flags wan_flags + ------ --------------------------------------- --------------- ---------------- ------ ------------------ ----------- ---------------- --------- ----------- + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.103 udp 2048 2048 80 + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.102 icmpv6 4660 4660 0 + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.102 tcp 2048 2048 80 syn syn + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb 153.153.153.153 102.102.102.103 tcp 2048 6070 443 syn syn,ack + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb 153.153.153.153 102.102.102.102 icmpv6 4660 8682 0 + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.103 tcp 2048 2048 80 syn syn,ack,fin + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb 153.153.153.153 102.102.102.102 tcp 2048 6070 443 syn syn + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb 153.153.153.153 102.102.102.104 tcp 8000 12022 8000 syn syn + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.102 udp 2048 2048 80 + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.103 udp 2048 2048 443 + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.104 tcp 8000 8000 8000 syn + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb 153.153.153.153 102.102.102.103 tcp 2048 6070 80 syn syn,ack,fin + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.102 tcp 2048 2048 443 syn syn + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb 153.153.153.153 102.102.102.102 tcp 2048 6070 80 syn syn + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.103 tcp 2048 2048 443 syn syn,ack + nat0 aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa 153.153.153.153 102.102.102.102 udp 2048 2048 443 diff --git a/autotest/units/001_one_port/061_nat64stateful/controlplane.conf b/autotest/units/001_one_port/061_nat64stateful/controlplane.conf new file mode 100644 index 00000000..735309ab --- /dev/null +++ b/autotest/units/001_one_port/061_nat64stateful/controlplane.conf @@ -0,0 +1,55 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "nextModules": [ + "nat0" + ] + }, + "nat0": { + "type": "nat64stateful", + "ipv6_prefixes": [ + "64:ff9b::/96" + ], + "ipv4_prefixes": [ + "153.153.153.153/32" + ], + "announces" : [ + "64:ff9b::/96", + "153.153.153.153/32" + ], + "nextModule": "vrf0" + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv6Prefix": "fe80::2/64", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/061_nat64stateful/gen.py b/autotest/units/001_one_port/061_nat64stateful/gen.py new file mode 100755 index 00000000..998c1016 --- /dev/null +++ b/autotest/units/001_one_port/061_nat64stateful/gen.py @@ -0,0 +1,325 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * + + +def write_pcap(filename, *packetsList): + if len(packetsList) == 0: + PcapWriter(filename)._write_header(Ether()) + return + + PcapWriter(filename) + + for packets in packetsList: + if type(packets) == list: + for packet in packets: + packet.time = 0 + wrpcap(filename, [p for p in packet], append=True) + else: + packets.time = 0 + wrpcap(filename, [p for p in packets], append=True) + + +# check lan (ipv6 -> ipv4). create state, use state +write_pcap("001-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.103", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.103", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.103", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.103", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.104", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/TCP(dport=8000, sport=8000)) + +write_pcap("001-expect.pcap", + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.103", src="153.153.153.153", ttl=63, id=0)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.103", src="153.153.153.153", ttl=63, id=0)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.103", src="153.153.153.153", ttl=63, id=0)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.103", src="153.153.153.153", ttl=63, id=0)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.104", src="153.153.153.153", ttl=63, id=0)/TCP(dport=8000, sport=8000)) + + +# check wan (ipv4 -> ipv6). use state or drop +write_pcap("002-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/TCP(dport=2048, sport=443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/TCP(dport=2048, sport=80, flags="SA"), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/TCP(dport=2048, sport=443, flags="F"), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/TCP(dport=2048, sport=443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/TCP(dport=2048, sport=80, flags="AF"), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/TCP(dport=2048, sport=443, flags="SA"), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/TCP(dport=2948, sport=80), # dropped + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/TCP(dport=2948, sport=443), # dropped + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/TCP(dport=2048, sport=81), # dropped + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/TCP(dport=2048, sport=444), # dropped + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.199", src="102.102.102.102", ttl=64)/TCP(dport=2048, sport=80), # dropped + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.199", src="102.102.102.102", ttl=64)/TCP(dport=2048, sport=443), # dropped + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.199", ttl=64)/TCP(dport=2048, sport=80), # dropped + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.199", ttl=64)/TCP(dport=2048, sport=443)) # dropped + +write_pcap("002-expect.pcap", + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.102", hlim=63, fl=0)/TCP(dport=2048, sport=80), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.102", hlim=63, fl=0)/TCP(dport=2048, sport=443), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.103", hlim=63, fl=0)/TCP(dport=2048, sport=80, flags="SA"), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.103", hlim=63, fl=0)/TCP(dport=2048, sport=443, flags="F"), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.102", hlim=63, fl=0)/TCP(dport=2048, sport=80), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.102", hlim=63, fl=0)/TCP(dport=2048, sport=443), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.103", hlim=63, fl=0)/TCP(dport=2048, sport=80, flags="AF"), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.103", hlim=63, fl=0)/TCP(dport=2048, sport=443, flags="SA")) + + +# check tc +write_pcap("003-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64, tc=0x01)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64, tc=0x02)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64, tc=0x04)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64, tc=0x80)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64, tc=0xFF)/TCP(dport=80, sport=2048)) + +write_pcap("003-expect.pcap", + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0, tos=0x01)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0, tos=0x02)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0, tos=0x04)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0, tos=0x80)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0, tos=0xFF)/TCP(dport=80, sport=2048)) + + +# check tos +write_pcap("004-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, tos=0x01)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, tos=0x02)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, tos=0x04)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, tos=0x80)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, tos=0xFF)/TCP(dport=2048, sport=80)) + +write_pcap("004-expect.pcap", + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.102", hlim=63, fl=0, tc=0x01)/TCP(dport=2048, sport=80), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.102", hlim=63, fl=0, tc=0x02)/TCP(dport=2048, sport=80), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.102", hlim=63, fl=0, tc=0x04)/TCP(dport=2048, sport=80), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.102", hlim=63, fl=0, tc=0x80)/TCP(dport=2048, sport=80), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.102", hlim=63, fl=0, tc=0xFF)/TCP(dport=2048, sport=80)) + + +# fragment not allowed yet. pass "atomic" fragment +write_pcap("005-send.pcap", + fragment6(Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/IPv6ExtHdrFragment(id=0x12345678)/TCP(dport=80, sport=2048)/("ABCDEFGH123456789012"*128), fragSize=1280), + fragment6(Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/IPv6ExtHdrFragment(id=0x12345678)/UDP(dport=80, sport=2048)/("ABCDEFGH123456789012"*128), fragSize=1280), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/IPv6ExtHdrFragment(id=0x87654321, m=0, offset=0)/TCP(dport=80, sport=2048), + fragment6(Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/IPv6ExtHdrFragment(id=0xABCDEF12)/ICMPv6EchoRequest(id=0x1234, seq=0x8765)/("ABCDEFGH123456789012"*128), fragSize=1280)) + +write_pcap("005-expect.pcap", + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0)/TCP(dport=80, sport=2048)) + + +# fragment not allowed yet +write_pcap("006-send.pcap", + fragment(Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, id=0x1234)/TCP(dport=2048, sport=80)/("ABCDEFGH123456789012"*128), fragsize=1208), + fragment(Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, id=0x1234)/UDP(dport=2048, sport=80)/("ABCDEFGH123456789012"*128), fragsize=1208), + fragment(Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, id=0x1234)/ICMP(type=8, id=0x1234, seq=0x8765)/("ABCDEFGH123456789012"*128), fragsize=1208)) + +write_pcap("006-expect.pcap") + + +# icmpv6 -> icmpv4. ping only yet +write_pcap("007-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/ICMPv6EchoRequest(id=0x1234, seq=0x8765)/"du hast vyacheslavich", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/ICMPv6EchoReply(id=0x5678, seq=0x4321)/"vitalya 2") + +write_pcap("007-expect.pcap", + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0)/ICMP(type=8, id=0x1234, seq=0x8765)/"du hast vyacheslavich") + + +# icmpv4 -> icmpv6. pong only yet +write_pcap("008-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/ICMP(type=0, id=0x1234, seq=0x8765)/"du hast vyacheslavich", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/ICMP(type=0, id=0x8765, seq=0x8765)/"du hast vyacheslavich", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.199", ttl=64)/ICMP(type=0, id=0x1234, seq=0x8765)/"du hast vyacheslavich", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.199", src="102.102.102.102", ttl=64)/ICMP(type=0, id=0x1234, seq=0x8765)/"du hast vyacheslavich", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/ICMP(type=8, id=0x5678, seq=0x4321)/"vitalya 2") + +write_pcap("008-expect.pcap", + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.102", hlim=63, fl=0)/ICMPv6EchoReply(id=0x1234, seq=0x8765)/"du hast vyacheslavich") + + +# unsupported proto and broken packets +write_pcap("009-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64, nh=0x1B), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64, nh=0x1B, plen=1), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64, nh=0x1B, plen=123), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/IPv6ExtHdrDestOpt(nh=0x1B), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64, plen=0)/IPv6ExtHdrDestOpt(nh=0x1B), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64, plen=1)/IPv6ExtHdrDestOpt(nh=0x1B), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64, plen=7)/IPv6ExtHdrDestOpt(nh=0x1B), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64, plen=9)/IPv6ExtHdrDestOpt(nh=0x1B), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64, plen=300)/IPv6ExtHdrDestOpt(nh=0x1B)) + +write_pcap("009-expect.pcap") + + +# broken packets +write_pcap("010-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, len=0)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, len=1)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, len=19)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, len=21)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, len=300)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*20))/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*20), len=0)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*20), len=1)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*20), len=19)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*20), len=20)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*20), len=21)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*20), len=39)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*20), len=41)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*20), len=300)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*40))/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*40), len=0)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*40), len=1)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*40), len=19)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*40), len=20)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*40), len=21)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*40), len=39)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*40), len=40)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*40), len=41)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*40), len=59)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*40), len=61)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64, options=("\x02"*40), len=300)/TCP(dport=2048, sport=80)) + +write_pcap("010-expect.pcap", + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.102", hlim=63, fl=0)/TCP(dport=2048, sport=80), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.102", hlim=63, fl=0)/TCP(dport=2048, sport=80), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.102", hlim=63, fl=0)/TCP(dport=2048, sport=80)) + + +# UDP. check wan (ipv4 -> ipv6). no state. drop +write_pcap("011-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/UDP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/UDP(dport=2048, sport=443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/UDP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/UDP(dport=2048, sport=443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/UDP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/UDP(dport=2048, sport=443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/UDP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/UDP(dport=2048, sport=443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/UDP(dport=2948, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/UDP(dport=2948, sport=443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/UDP(dport=2048, sport=81), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/UDP(dport=2048, sport=444), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.199", src="102.102.102.102", ttl=64)/UDP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.199", src="102.102.102.102", ttl=64)/UDP(dport=2048, sport=443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.199", ttl=64)/UDP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.199", ttl=64)/UDP(dport=2048, sport=443)) + +write_pcap("011-expect.pcap") + + +# UDP. check lan (ipv6 -> ipv4). create state, use state +write_pcap("012-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/UDP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/UDP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.103", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/UDP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.103", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/UDP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/UDP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/UDP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.103", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/UDP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.103", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/UDP(dport=443, sport=2048)) + +write_pcap("012-expect.pcap", + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0)/UDP(dport=80, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0)/UDP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.103", src="153.153.153.153", ttl=63, id=0)/UDP(dport=80, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.103", src="153.153.153.153", ttl=63, id=0)/UDP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0)/UDP(dport=80, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0)/UDP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.103", src="153.153.153.153", ttl=63, id=0)/UDP(dport=80, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.103", src="153.153.153.153", ttl=63, id=0)/UDP(dport=443, sport=2048)) + + +# UDP. check wan (ipv4 -> ipv6). use state or drop +write_pcap("013-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/UDP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/UDP(dport=2048, sport=443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/UDP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/UDP(dport=2048, sport=443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/UDP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/UDP(dport=2048, sport=443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/UDP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/UDP(dport=2048, sport=443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/UDP(dport=2948, sport=80), # dropped + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/UDP(dport=2948, sport=443), # dropped + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/UDP(dport=2048, sport=81), # dropped + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/UDP(dport=2048, sport=444), # dropped + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.199", src="102.102.102.102", ttl=64)/UDP(dport=2048, sport=80), # dropped + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.199", src="102.102.102.102", ttl=64)/UDP(dport=2048, sport=443), # dropped + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.199", ttl=64)/UDP(dport=2048, sport=80), # dropped + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.199", ttl=64)/UDP(dport=2048, sport=443)) # dropped + +write_pcap("013-expect.pcap", + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.102", hlim=63, fl=0)/UDP(dport=2048, sport=80), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.102", hlim=63, fl=0)/UDP(dport=2048, sport=443), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.103", hlim=63, fl=0)/UDP(dport=2048, sport=80), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.103", hlim=63, fl=0)/UDP(dport=2048, sport=443), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.102", hlim=63, fl=0)/UDP(dport=2048, sport=80), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.102", hlim=63, fl=0)/UDP(dport=2048, sport=443), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.103", hlim=63, fl=0)/UDP(dport=2048, sport=80), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.102.103", hlim=63, fl=0)/UDP(dport=2048, sport=443)) + + +# check collisions (tries) +write_pcap("014-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", hlim=64)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.103", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", hlim=64)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.103", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", hlim=64)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.103", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", hlim=64)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.103", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.104", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", hlim=64)/TCP(dport=8000, sport=8000), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.102.102", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", hlim=64)/ICMPv6EchoRequest(id=0x1234, seq=0x8888)/"du hast vyacheslavich") + +write_pcap("014-expect.pcap", + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0)/TCP(dport=80, sport=6070), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0)/TCP(dport=443, sport=6070), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.103", src="153.153.153.153", ttl=63, id=0)/TCP(dport=80, sport=6070), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.103", src="153.153.153.153", ttl=63, id=0)/TCP(dport=443, sport=6070), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0)/TCP(dport=80, sport=6070), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0)/TCP(dport=443, sport=6070), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.103", src="153.153.153.153", ttl=63, id=0)/TCP(dport=80, sport=6070), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.103", src="153.153.153.153", ttl=63, id=0)/TCP(dport=443, sport=6070), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.104", src="153.153.153.153", ttl=63, id=0)/TCP(dport=8000, sport=12022), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.102.102", src="153.153.153.153", ttl=63, id=0)/ICMP(type=8, id=0x21ea, seq=0x8888)/"du hast vyacheslavich") + + +# check collisions (ipv4 -> ipv6) +write_pcap("015-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/TCP(dport=6070, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/TCP(dport=6070, sport=443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/TCP(dport=6070, sport=80, flags="SA"), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/TCP(dport=6070, sport=443, flags="F"), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/TCP(dport=6070, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/TCP(dport=6070, sport=443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/TCP(dport=6070, sport=80, flags="AF"), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.103", ttl=64)/TCP(dport=6070, sport=443, flags="SA"), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.104", ttl=64)/TCP(dport=12022, sport=8000), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.153.153", src="102.102.102.102", ttl=64)/ICMP(type=0, id=0x21ea, seq=0x8888)/"du hast vyacheslavich") + +write_pcap("015-expect.pcap", + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", src="64:ff9b::102.102.102.102", hlim=63, fl=0)/TCP(dport=2048, sport=80), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", src="64:ff9b::102.102.102.102", hlim=63, fl=0)/TCP(dport=2048, sport=443), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", src="64:ff9b::102.102.102.103", hlim=63, fl=0)/TCP(dport=2048, sport=80, flags="SA"), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", src="64:ff9b::102.102.102.103", hlim=63, fl=0)/TCP(dport=2048, sport=443, flags="F"), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", src="64:ff9b::102.102.102.102", hlim=63, fl=0)/TCP(dport=2048, sport=80), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", src="64:ff9b::102.102.102.102", hlim=63, fl=0)/TCP(dport=2048, sport=443), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", src="64:ff9b::102.102.102.103", hlim=63, fl=0)/TCP(dport=2048, sport=80, flags="AF"), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", src="64:ff9b::102.102.102.103", hlim=63, fl=0)/TCP(dport=2048, sport=443, flags="SA"), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", src="64:ff9b::102.102.102.104", hlim=63, fl=0)/TCP(dport=8000, sport=8000), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:bbbb", src="64:ff9b::102.102.102.102", hlim=63, fl=0)/ICMPv6EchoReply(id=0x1234, seq=0x8888)/"du hast vyacheslavich") diff --git a/autotest/units/001_one_port/062_nat64stateful_multipool/001-expect.pcap b/autotest/units/001_one_port/062_nat64stateful_multipool/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..e39b29759d2be9dccae9f1bc14873e6ec221737e GIT binary patch literal 37912 zcmb8&Rj^RkvW4M|ySu|ig1fszaCZVBXo5pfX~Amp{5Crz5%xN+lvfY1Q}75*9fCn^L@9Plvh|K9&|{wApzQV@~Sm{L=u zpdzIJ5y?i6jG!Vrt}k1D3OwzQUj#WA|*4WACba{ zl+={!BZUDgA&HUZljPR2M0NNQq3T4pKys5}HzNq(~wqFr`{ZkwuDc zN;Q$9h!oG1Y9K`wDXuA1M~Ws=98;=>6kVj)rc@OvhDfnYsR~j|kz$%sWu#al#W1Bx zNU=qVZb}uA;)oQ@lqw*_6)CDIl}CyvQWR4vhZJ9=$fi^lDS=3lOsNb~LXjexQfZ__ zB1JHzQb>tK3U5l^BP9_joGFz=3KS`D#_jKBRR2Ej{?Mp86W!lv7@$^df!w>U`tO%!8Ccq>rYQ8!4kmA51A1 zQYMk!n^I1s%p$!rr5s3EM0#sV*^#n}^v0C3A!QTkwJBvq$}Z9?Q_6yrL!_6clo=_f zNH0t&6H+dbo|{req}(DsGo=hjc|>|@O6igEiuA;k(jny&>9HxLManPIBU4I)R6wMM zrj#0~phyo)DHT#7k^VNNlt_g|x^GI~Ar%qno++h3Dk{=lQ%a6hOr$%elnkl3NViQX zDN+fMZkbXbQc00+no<&^??t*{N{Nw5iFDnR5+Riq>6$4eL@FcFRZ~iUR92)brW7Bk zoJf~VDIQXJkuI51T%-yjT{NXQNEJo8U`nx(Dv5O7lwu)O7U`TR#YCzi(pgiAfmBtb zGo}|0A)fVZPDMdu8Bhpb* zihxvCq$8#j9_a^>4x3UqqYYA@0TQ+kQ?t4Qlj=><{;k=B{gbEJ+Utu>`*NS#DlV@gkvI*YX0 zl%61U5owhvJx1y((n?c$gw#!>6{hqMsk=zaP3Zwr50RFc(%(ouMOtb~_mO&uw8WI| zA@vq%u_@g}>Lb!3Q@VrHSEPlebQ`IkNDEBq7E*ta=9|(@qyZw$Go>3y14Wu^O4pGF zi8RNQt|1K;X|^d{MH(W~@1}GGX{boEOzASxFp*}O(j}zfBF!+Ri%26xnr=!LkVc9$ z&6Lg~jS^|9DV;+aEz%TII*T+$q{*gq25GEFlT7I}(m0VOn$jtx-$a^VN+*%Vi!|Pp zP9RMX={Hk4jxMgtB^K`)ZUah-Ih*Z~oe`<3DUCro zD^e9x8jW;Lq{^l=3hBH^l}u?Q(gl$!n$ifQiy~DprQt}IL@IAe!;mhERL+!!B3%)w ztSJpax++o`QyPqPO{CJMGzjUsNTp0^AkqzyzBi=-NH;|)X-fT(Zi!UFl=>mv7OA)? z^+mcPQZZBNgLGG7GbMOsN;reUS>AQctA6MJi-UJ&+!VRM3>VBRv$UfGKrD zdL&YQQ|gNJSfqTW)CK8@NO?`EGtyI$@|aR5q-P@KHl>b8&qc~*N*$11h?LWmenomI zQVvsUkMv5U?55NX>9t7NOsOr>8;3AzerAA00L^^3o4Us~Mbi$N=LJB3)aZ_r56k4QXrt~9H7?F;eQhlVb zA{{ZMdPw0!I&4ZmAcYs{kSWzgiXhTKQ>ud$QKSQ=R2wOhNc&Bx7E)x9_L)*mq$nco zHKiIzQAPU8l&T{|6KRhrRYQs{(x0YO6)A>DyG^MIQcRI{nNnq>SR(B-rAkP#McQFX z6_MhIwB3{{AjK7Fn< zN_mhnh_uL*awBCFX`w0QLdqo40#nL~lv$+trj!FIi%9cKDLYbDk>;9GHl%DK%`v5{ zNZCc2ZAw{?a)|W1DP=~=Dbg%c%7m0lq?x9a5h=GwGfXK1QXY|}n^JnDydq6ArF2O7 zM4D3fkznNnh;QX-8sr9?=jMH*pB z36aW(G~ARDAe9wqm?_0aDksuVQ;LUFUZf$W6c?$2NP|r&4pK#t2ANW9q)H+UG^JQb zl|>q0N->eDh}7SdVjxu&sh=rDN2(@LUsH;PR9&P#rW6&ahDg0lDGE|ek$Ra@WTaXm z^)#hONVP@kVM-B^>WI|clp-M26{(vkg-7~9q^_nE4ym3-+L~3hFL6Mq@)W(#8 zAT<-IwJ8N4{VY-|Px`n2lSnO1=@U6M7pa9QeMD*@Qgc)KfYef?UrgyeQY(>uHl=q+ ztwm~PN^g4a&yhNc z)WDRUA$1bzM^k!=)LEqZrt}10p^bRVggNHtCA9#U_SYM9bpq&^~5H>EpBeMPEfO1F{viB#2;ZXxv-sfsDx zL>eGcWmCF=G*F~UrgR-?kVq9x=^D~tkt&$dRiq&zl{cj;NJB*`XG)imhKW?xlrA9+ z7paUXT|^ooQfX7VfHYF1Ql@ksX_QFco6*aQkqVpAaiobN6*8q`NRvb=Xi7(sCW}twP!$QW8^I ziL_Cq#HO?YX_H8aOldjNW|0z_(lVqiA|)`TrAS*vif>9wkp2)Uo+&Lx+9pz5Q(Aq+KG#G^Ke+yG4p&N^_C^6e+qX%|Y5DQZ!SVjr5mD zQBCQ0q`e|VF{N2Z`$URtN;8r6ixkO}W*{99DWWM&M>;4{1XG%ZbV#J|rZg4lut?!d zX$sO2k;0nNWTc}ag)yZ`NXJA9ZAuf7j*Aq^lqMjZ5GkZ7jYm2uQV3J}4e69f!A)r# z(rJ-`nbKIKGa>~wr7=inMG9g{qmj;u^e^;He*nKa3hDfROE*9NOZ~Gk!sbX|U|>L$ zz$`_p_6`X6(r53>2IK#%01AY>IuhxENS{n;1ky#3KAO^Sq)Q@wFr{HgmqmJSN<)#Z zi1f~sh9F%P>8&XZM!F`_8&evDbX}y^rZf=ghDfhWX#mnqkzSfof23O?y)dPINVi3L zZc2TT?uhivl=>ju73rxd^+viU(i2nag>+w}$EMU1>2Hx9nNkm=2O>Q*rS3=%MS5UL z-H;xM^tUN>MS3jKeN*a!^hBh4rqmhfsYrKCsT0yOk?xpMN2KQ>-8Q8TNH0XXWlFyy zy%g!DDYZv>CDIL3YKQb%r0b^C7U_*h*G#Dm(p!{0)X)gA~uR*7lJ4jDj_Z1-JMbr(v5U?cXxLyUD7Go9az{MysOWvv-sX$ zZ+&a#+%x;!Grw7LW}Vq<&i-bf*|T;|@`Mx#N#o+hgoI>C2Z_&R|9&K-PM4){mB0Rx ztWQEhqk(VM|MMVC%KS?&83~OpPW$V9iGP|jNl3UdA)$QIarxwF6AqtCIui6`(9eo` za_BFM`eo41hr$zm8=%++ICG?Y`eg*UsqJAaxdN0ezdO-wFLiQNIiN3!;8E^sSKUQ067`3muN3u%p|242N1!hk z^+%yE6ZOZSFBSDn(3gn%iTab!7m9jj=nF(W3-tM-o)!8$QO^c_uBbl+ zeU7MShdx`>b3mUZ>N%m$6!l!tXNY=k=+i|#5A=V2B^G`M&I^62IQOTaPZ9Ne&?k#} ze&~}#y#VxyqFxaC1W_*peY~g_hCWWzi$EVM>P4ZC5%prwM~ixK=%Ylv1oV-jUK08U zQ7;93xTu$gK1|fhKp!gVWuXrd^>WY$i+XwJgG9Xo^ns#Y5&8g8uLQlns8@#GPt>bG z?xj?+m@ZsCR*0Pt?0YuPf@^pw|)g?$B$CdJpKe zME!Z_HATHA^ctex3wm`??+v}0sP}}Q5SFD>fBp_dZ%5ztGD`bg*{M12(W;-Wqp zdNENS1HGuIkA+@D)W<HiqCOdVK2e_n{b^C33O%o= zPlKLE)TcwwE$TC%=Mwdq&~u9VEa*8zeKz#$qCN-uQ=&c>dNxs?2R*B(&xf8x)E7X{ zEb0rPKPl>qpg$q%i=jU*>Pw(!67{9f9~1Ru&>t1`<@^!r79J@oXVz5#kVQQrvtK2hHUJ*}v3hJLT8Z-IV~sBeXS zx2V4W{Vq{|5&E5?z76^vqP`va?V`Q|`fZ}V6Z);9z6<&-qP`pY&7!^sdKyvR3;iZh z-v|9hQQr?ewWuF}euJpL1pRtZKL|aQs2_rUov0s%eyykfqW%T+PeuI#^iM?nOX%lC{VV7ni~85lKN9tCpnoXp-$MUD)W3uNzNmi> z{XJ3t0s6b5{v-5vMExh|Z;SfR(BBgEU!cD!>c2vNL)3qR{<^6D4*fMz{{#A~qJ9zj zD^Yrb^#4?Z|Lgwmi{n~|P)~O0+!x2S5TTwNdRz+;>X$*!B!2EGpvSck;oL8W9@j#I zdP?YVEkvka0X?pT2=yzW$F&fleiihL;+nY{dRz+;&ixwbaVBwLyv1ALj4iwaVpvSckp`HnPTniEEk3)}ZAwvBL=y5GXs6PokX|X3hN3ZwHm+Fh+T8MD&S)j+Y z5TTwGdRz+;>e-;jwGg5H6!f?jBGj`(k82@9JqPr-79!MhLXT@9LOmDsxE3PRb3>17 zAwoS5^tcux)bm1*Yav4YY3Ok+M5yP39@j#IdVc6}EkvjnfF9REgnB{faVq0**>h++X67~AfPl|d2=qE(IA@t*-{tWbEqTUGlQBiLU{fMYH zfqq!jn?gS%>dl}Z6!mAJza;9-p&tG%U4$!xWdPnFlih3vLFNk_)=vzg-3-m3b-WB?0QSSzQlc;xx zzERYBK;Izh&qH4?>OG;a6ZKxu*NS>?=xap15A@Zd-WU2RQSS$RrKtCZzCzRoKwmEE z1EDVy^+C{=iuz#aOGJGL^u?k+6#61j9|nD)s1Jv}K-5P-pD*eoq0bZbQPAg#`e^8L zM12hO*`huc`Ycf&2YsffkB2@()F(inF6tAZPZRY?(5H&}Wav{weG2r+qCOS+BvGFR zeWIvOhdx2nXFwk>>NBB_6ZKip$BO!F=wn2E4)oEYJ{S5ZQJ)8Wq^Qq_K0?$NKp!sZ z3!x7a^+nK!iuz*cLqvTE^ueOO6#5`hUj}`ks4s^;K-5=2?=R{rq4yK@RnYs2`fBKX zM12kP-lD!1dM{C52fe4LuZRA;sBeJYL)14y?=I?_pm!7X&Ct7w`WEP2M13pt&Z7PT z^iHDwBJ_@;z72W@QQr=|y{PYi-cHnaLT@YTyP&rb_1(~0i~1hu&x!h8=&eM3AM}=@ zz8`uEQ9l5^xv0Mc{aH~z2)&u8AA;Ug)DJ^%BI-w=Hx~7y&>M;RG3d{T`f=zDMg0Wy z2BLlvdVNtp1-+iApN3vn)XzY#BkC_huPy3lq1O`ibI@yw`YX_Di2AG0tBd+;(5s31 z>(Hx;`Ww)zi29q*D~tMD&?|}h+t4eD`a94oi2A$G%ZvJZ(94PX`_RjZ`UlX$IwfP`g!OjMEw)!#YO#7=*2|+Gw4M{{d4F=MEwisg+=`W^g^QkCG>)# z{uT5BqW(4X{G$F1^n9ZJE%c{F{X6J+Mg4o|c|`pO=($DxN9egk{U_)-Mg3>!IYj*z w=-Ea6SLjcP`ft#)iTdx*vx@p3(6fm8Md+EM^_2e=67T<>@=|?qhJ=Lw0M_65xc~qF literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/062_nat64stateful_multipool/002-expect.pcap b/autotest/units/001_one_port/062_nat64stateful_multipool/002-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..ca8dc918e8f55e001556f9367b6353f817d326ba GIT binary patch literal 48152 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 UPt?;2{V&wh2>mqbsS^_Z2cmaKQUCw| literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/062_nat64stateful_multipool/002-send.pcap b/autotest/units/001_one_port/062_nat64stateful_multipool/002-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..fb2f96eae3d32cd36f624f05023819ea9f86fce4 GIT binary patch literal 75800 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 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/062_nat64stateful_multipool/003-expect.pcap b/autotest/units/001_one_port/062_nat64stateful_multipool/003-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..9c43fdba5acaeaf95f8531198dbe6526027bbb40 GIT binary patch literal 151576 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 Y`XVIfgPJ}h(!P=un#DD>QYWeZ1I`Q0WdHyG literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/062_nat64stateful_multipool/003-send.pcap b/autotest/units/001_one_port/062_nat64stateful_multipool/003-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..f0c7567f28e5de52a2ea05bac33a2f7e39e4087c GIT binary patch literal 192536 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 M>P_f{`evv8KN8Y5^#A|> literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/062_nat64stateful_multipool/004-expect.pcap b/autotest/units/001_one_port/062_nat64stateful_multipool/004-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..040af78db40d942e527873d5550d08ced7ff2a91 GIT binary patch literal 616 zcmca|c+)~A1{MYw`2U}Qff2?5(pFFmq?DAD7zCA!T|yff7*237xH2$kfE3!ZrQV-8 zbCyHet7=`A0EPgN7zhL~DKL}qncE>h+LC^enWNBLb6R_L^Ejt*(Nce enKYkllbF#=nn$)tENCXpCEFxcG?V5qFaQAfTV3w} literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/062_nat64stateful_multipool/004-send.pcap b/autotest/units/001_one_port/062_nat64stateful_multipool/004-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..ae2d9b98c4bfabb60d8f3b4cdb276221b337f38a GIT binary patch literal 776 zcmca|c+)~A1{MYw`2U}Qff2?5(tc3PAgE;Q5(<`JY-C_aX}g;M;)t+0tb&5wP{5G# ze>PYhkVtz~t;-MqgisK`q`)9N3C5#_>CFF8P3M11P1Av9p}PGMRZV9^GyNe|O=m(g d{Q*@?XGSyqK2=R;K{NdxRZV9_GyN_D0|2vuv4;Qv literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/062_nat64stateful_multipool/005-expect.pcap b/autotest/units/001_one_port/062_nat64stateful_multipool/005-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..e1e4f2501074163ca9195dedb38488f277afd092 GIT binary patch literal 776 zcmca|c+)~A1{MYw`2U}Qff2?5(tc13qyz;883dJ#T|yff7*g8qCIE#PMA+;ZQvS~d zF+m{hRkiLaDA)}J3;{q01p!P748oIOJnERv40JIBfK2Cq4C7J9bcAVOw?9JgsS+~q ypaz@%kjkbr!OR1j{s6|KQphmF%mbT#AI77S>F^{8HvJxzO=pFf2R8jK0|Nk7*s~7+ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/062_nat64stateful_multipool/005-send.pcap b/autotest/units/001_one_port/062_nat64stateful_multipool/005-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..15390071294a5eb5ad07afbaf579775c1983c04b GIT binary patch literal 616 zcmca|c+)~A1{MYw`2U}Qff2?5(pFH+AgE;Q5(<`JYGhzI!NK6lz@PzA>cEzAFYQ&e z?#!9992f#v0$`d0m=qXF17SSUO=1VS1Oh-N6)uADNH+=LJFuG;QeYB1Xuu{dpui+1 pm|n0+^I<$Pe8&va3pQyUj7Nq^@PGoFG?xOCSYdj>Ce2}B0031iTF(Fg literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/062_nat64stateful_multipool/autotest.yaml b/autotest/units/001_one_port/062_nat64stateful_multipool/autotest.yaml new file mode 100644 index 00000000..2289197c --- /dev/null +++ b/autotest/units/001_one_port/062_nat64stateful_multipool/autotest.yaml @@ -0,0 +1,23 @@ +steps: +- ipv4Update: "0.0.0.0/0 -> 200.0.0.1" +- ipv6Update: "::/0 -> fe80::1" +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap +- sendPackets: + - port: kni0 + send: 003-send.pcap + expect: 003-expect.pcap +- sendPackets: + - port: kni0 + send: 004-send.pcap + expect: 004-expect.pcap +- sendPackets: + - port: kni0 + send: 005-send.pcap + expect: 005-expect.pcap diff --git a/autotest/units/001_one_port/062_nat64stateful_multipool/controlplane.conf b/autotest/units/001_one_port/062_nat64stateful_multipool/controlplane.conf new file mode 100644 index 00000000..f0f2716f --- /dev/null +++ b/autotest/units/001_one_port/062_nat64stateful_multipool/controlplane.conf @@ -0,0 +1,61 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "nextModules": [ + "nat0" + ] + }, + "nat0": { + "type": "nat64stateful", + "ipv6_prefixes": [ + "64:ff9b::/96", + "61:2345::/96" + ], + "ipv4_prefixes": [ + "153.153.153.100", + "153.153.154.0/24", + "153.153.155.0/25" + ], + "announces" : [ + "64:ff9b::/96", + "61:2345::/96", + "153.153.153.100", + "153.153.154.0/24", + "153.153.155.0/25" + ], + "nextModule": "vrf0" + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv6Prefix": "fe80::2/64", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/062_nat64stateful_multipool/gen.py b/autotest/units/001_one_port/062_nat64stateful_multipool/gen.py new file mode 100755 index 00000000..9c233be8 --- /dev/null +++ b/autotest/units/001_one_port/062_nat64stateful_multipool/gen.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * + + +def write_pcap(filename, *packetsList): + if len(packetsList) == 0: + PcapWriter(filename)._write_header(Ether()) + return + + PcapWriter(filename) + + for packets in packetsList: + if type(packets) == list: + for packet in packets: + packet.time = 0 + wrpcap(filename, [p for p in packet], append=True) + else: + packets.time = 0 + wrpcap(filename, [p for p in packets], append=True) + + +# check lan (ipv6 -> ipv4). create state, check source ip +write_pcap("001-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.102.0.0/120", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="61:2345::102.102.0.0/120", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="61:2345:6::102.102.0.6", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", hlim=64)/TCP(dport=80, sport=2048)) # dropped + +write_pcap("001-expect.pcap", + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.0.0/24", src="153.153.154.102", ttl=63, id=0)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.102.0.0/24", src="153.153.154.102", ttl=63, id=0)/TCP(dport=80, sport=3923)) + + +# check wan (ipv4 -> ipv6) +write_pcap("002-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.154.102", src="102.102.0.0/24", ttl=64)/TCP(dport=2048, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.154.102", src="102.102.0.0/24", ttl=64)/TCP(dport=3923, sport=80), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.154.103", src="102.102.0.0/24", ttl=64)/TCP(dport=2048, sport=80), # dropped + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.154.103", src="102.102.0.0/24", ttl=64)/TCP(dport=3923, sport=80)) # dropped + +write_pcap("002-expect.pcap", + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="64:ff9b::102.102.0.0/120", hlim=63, fl=0)/TCP(dport=2048, sport=80), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", src="61:2345::102.102.0.0/120", hlim=63, fl=0)/TCP(dport=2048, sport=80)) + + +# check lan (ipv6 -> ipv4). create state, check source ip, check source port (1024 .. 65535) +write_pcap("003-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.199.99.99", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa/118", hlim=64)/TCP(dport=80, sport=4444), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="61:2345::102.199.99.99", src="aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa/118", hlim=64)/TCP(dport=80, sport=4444)) + +# 003-expect.pcap - dumped + + +# check source port +write_pcap("004-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::102.234.123.45", src="aaaa:aaaa:aaaa:aaaa:bbbb:bbbb:bbbb:bbbb", hlim=64)/TCP(dport=80, sport=[80, 1023, 0, 1, 2, 3, 4, 5])) + +write_pcap("004-expect.pcap", + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.234.123.45", src="153.153.154.64", ttl=63, id=0)/TCP(dport=80, sport=[80 + 1024, 1023 + 1024, 0 + 1024, 1 + 1024, 2 + 1024, 3 + 1024, 4 + 1024, 5 + 1024])) + + +# check wan (ipv4 -> ipv6) +write_pcap("005-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="153.153.154.64", src="102.234.123.45", ttl=64)/TCP(dport=[80 + 1024, 1023 + 1024, 0 + 1024, 1 + 1024, 2 + 1024, 3 + 1024, 4 + 1024, 5 + 1024], sport=80)) + +write_pcap("005-expect.pcap", + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="aaaa:aaaa:aaaa:aaaa:bbbb:bbbb:bbbb:bbbb", src="64:ff9b::102.234.123.45", hlim=63, fl=0)/TCP(dport=[80, 1023, 0, 1, 2, 3, 4, 5], sport=80)) diff --git a/autotest/units/001_one_port/063_nat64stateful_multimodule/001-expect.pcap b/autotest/units/001_one_port/063_nat64stateful_multimodule/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..b0de9d1d1ef220bce5c439caf2228412f44508d7 GIT binary patch literal 284184 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 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/063_nat64stateful_multimodule/001-send.pcap b/autotest/units/001_one_port/063_nat64stateful_multimodule/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..5246ebc6688a8355ad8448a78883a1f4170aa8d8 GIT binary patch literal 360984 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 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/063_nat64stateful_multimodule/002-expect.pcap b/autotest/units/001_one_port/063_nat64stateful_multimodule/002-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..76766fff75f82d61b82b9b94f525ed293e56d916 GIT binary patch literal 72216 zcmbu|1(2168piRZJC^S5?i6WIx{+=q6r_>vPC>f6OIqn}q!f{oP`U(ZE{qqr?>cw> zygp}U*XSI`rn9!Jm(37JcDCj9rk1FUXQI8_%sZftB=&4bUBS2Uq&xCqtLC=hOC_&GH`umeX{`);E>LG+<&xU$% zLC=o*|C|_epBKx4`ujuo-|sm|ANcyb-rJk|*mI%&@~!JJ6I5bA#ldSTQb2zn9J?+bcS)b9y; zG1Tu0dU4e62zm+BZwq=!)Ncv;C#c^P^iNU0A?T%0zb@#dQNJeWWl;Y^(95F!yP%gt z{i>jsNBxSRS3v!;pjSlwlAu>Y{Wn3cjQT}EuY&poL9dGXc|os+`Z+c0qjE!0m7dTrEy7W6u(|0L*jQ9mW<^-w=4==D)QA?OWIKQ8DEQ9mZ= zjZptl&>N$ERM4BCenillqJCJ=KS%wLpf^MPprAKL{eYmiKz+ZUw?uuPpnrk-UP1p7 z^*w^#3iaKB-Wv5?g8miiI|aQB>N^CzE$Z6^y&dY?1id}#TLrxX>RSZ8BkG$4y%Xx2 z1idrrKM4BQsDCf$T~OaB=v`6YAn4stUoYt0QC}zMJy2gO=si(iBj~+QUoGgpQU6ZR z`=Gu`(EFmkQqcRMzCzIZqrP0w2cW)8&ZzC_RmqrOK*i27tfpM?4(L7$BJL_wc|`UF9riu!m#pN9H4L7$HLw}L(c^|69J z6ZJ8IJ`4441bsH@qXm5q>Z1gGF6tu%eIDu~1bsg0!v%c->ca$mA?iZ~eG%$I1bs2; zg9UvF>VpJ*De40SeHrQl1bsQ`{RMpm>iqLqIy9@ey)Vm4#2GqL>`bN~d2zpTbAJ-BY__d(_5R?ykrILZ21$`6hodkU| z>Kz4r3+f#NeJkqi1$`Up?F4;0>TLym2kLDEeJAQ)3HmP7TMPPb)LRMq9@M`S^u4Hm zA?W*1Zz<^eQEwsW2T*S==m$}6Cg_Jy|6I@yqux}|kD%T}(2t_tSkQk&y^)|FL%pG( zA4k1`pr1g!zM!8(y`G?-LcOk_|AcxSLH`-`+Jb%>^;&}d3+gom{S4|g1pQakKNIw` zs8<*CbEsDn^z*1!74!?JR}u7!s8<&B-%zh4=$BBhDCn0_uOR4GP%kg&S5Yq~=)a?0 zR?z=Iy^Nq=L%p=1Uq`)^px;3KQ$fFp`X_>Z3-ywMejD`?f_?|};(~q`^V*XTA?gJM{SoRP3;JKE7ZCKvsDC8rPf*V<=uc74C+N>m&nxK9 zQO_gjFHp}d=r2*vCFrkE&*{^Xzx(&#L$3e+(z$CJJs2JPOXsd_^x&vFcWtAGK;5}( z8$BfI&RyH+p-^}3+C~qJx^veydKlE5ySCB8qTWk*Hibjoxoewa50AQY*EV_t)SbJw z(IcYn+_jA!33cbLZS=^fJ9llPM?u}WYa2Z(>dsx;=z*v^cWt9bL*2P+8$CMe&RyH+ zF;I8z+D4Cwx^veydMwnPySC9|qwd_bjUESe=dNw^xTrgKZKKCS-MMQUJwEErUEAmh zPv7*EV`8)SbJw(Nm-D+_jCK2KD;F*Y9ajckbHe*wdlz+_jCK9(CugZS)MN zJ9llPXGGn(Ya2Zi>dsx;=$TP>?%GDrg1U3pHhNanox8Ttv!U+XwT+$~b?2^a^c<)= zcWtBRMBTY-8$B25&RyH+xlwoS+D6ZVx^veydS29>ySCBuq3+zZjh-KM=dNw^k5G5+ z+D0#cx^vey`p2j{cWt8=MBTY-8@&+f&RyH+g;96z+D0#ex^veydQsHh?HC{ST`Y`V z40Y$OZS>-(J9llPmq6XQYa6{J>dsx;=%1ioNcj5wQ`DWiwmJ4vs5^IUqnAeAxoaD} z4C>BZ+vsIcckbFoFNeBw*EV{2)SbJw(JP?t+_jBf5q0OTZS+d0J9llPS4LggwX2|> zLwKF3ih6cIuZDUyL9dQ_Rzd#^^(=y31NF>;UK909f?f;tjDlVp^$dbu2le!VUKjOr zf?f~xw1QqA^)!Os0QJ;@-VpUvg5C)Al!D$E^%R2M1oh;C-W2s@g8n(`Nd>(b>PZB> zIqHc8y#?xt1idBd2?hNN)DsB$m#D`V^j4_H6ZF=o#})LiP>&<%ZBUOb=xtGtCFt!? zk16QwQI8?$9Z-)h=p9jyCg`0|4;1vys7Dp_uThU8=v`2cEa+WPk0j{bP>(3+-BFJq z=si#mFX%l{4=3ooP!B8Uy-^P%=zUNRE$Dqw4<+dRP!B2S{ZS7g=mSs>F6aYM4<_h? zP=Akq(DyYr=kx}X{^Hep{>>Qr-$67mFfbr6S@vR8dj|wG9&on)o8J^8bipJ6MjwLu z%Qt`U@0(j6iu#MU_P^MhhN1pk(1)Y`OwdQ5{#4LMqW(nCN1^^$&_|>Gm!N-x`XfOf zgZe{3AB*~*g8nV)4+MQ2>h}eGJnHuZeFExt1$`pwcLaSB>bC`bGU~SkeG2L~1$`>& zHw1ke>emH*I_lR1eFo}(2>MLae;4#ws9zQI*{EL;^f{c<6rE$YVveI4pQ3i^7~j|%z*)Q<@IM$``rdQkiy*MEO; zNYH->$_Ksv`-_8uz6tdMg1#B`{er#)^?icA74^M>z76#~g1#N~-GaUY^<9F#6ZM^f zz6+g1#U1&4PXa^-Y3)5cMAf{SfNk3;JQyHwyX@ z)HewFQPkH9`j4ou6ZB)KuNCy;sIL+96R58i^pmK6C+Me8UnS^2p}tbke@1hlEs66$jW z{W9uv1pNx?vjzPs>azs>chqMJ`X8vz5cF%PPZ#v-s81908>mke^qZ(p5%gQAPZsps zs815~JE%_-^t-4}5cGSfj~Dd&sE-r$2dIB5=zpRh zJqqg19@ywnQFr#hMh`^Y*#jFr8tS+Iet^IE(fxRjj`}S@kAb?g2R8RiOw^q{u+d|o z?(Bh$9vgLM4{Y=}s5^ULqsK+v*#jFr9_r2>*y!<5clN+WPk_3!2R3>_)SW%B(G#KW z?17D*7>>2R6r^0d;2&Z1jw%J9}WGXF}cC z0~dqe6=vh#A_P|EZin_B0HhMPH4-1d??5Mvx&-E|LP%0~@^p>dqe6=oL|S_P|E3g!(e!@m?AArGj1sb!QK3?wP8nJ9}WGS3}*| z0~@_M>dqe6=%1nP?17D519fK)Z1kF_J9}WG*FxRd0~@_I>dqe6=ygzc_P|E3i@LK1 zHhMkOojtJ8>!UtHcol1ay0Zs1$KDWiXAf-jMyNY`V52ui-Pr>hy$R~h9@ywjQFr#h zM*kdjXAf-jW~e)RV52uj-Pr>hy#?yygy(8Y)SW%BIrcA5clN+W{}Od)4{Y>Ss5^UL zqqj!g*#jH>E7YAmu+iI~?(Bh$-WK%{!sERi>ca)SJ?hRL*xWN6PEavj;YM zC)AZ5xHIa5gum6VQ6DJiT~Hq&=v`6oFX-J+?=si*IE$F>a?N)`n+y5`)SC(VMASbQ^hu~U74*rdHxcwHs5ch$si-#+^l7L!6!ht+HxTq0 zsMiZ=*v*ABG#{;8m^NBt8)-++2aLEnga2|*8v|Ks}a9f}M34?+2$*MIL&Owc!> zUR2OGqh3VNx1e5F(6^#qNYJ;TUQp1tqyDj=??AnPpzlQeBSGJVdVWFQje0&o--CKy zLEnpd9zoxSdTv4Ak9saaKY)5pK|hFk4naSJdUioSjCwXfKZ1HzK|hLm7D4|J^~{2P z4E0QcejN3Tf_?(^41#_V_4I;%3iWh?{uAnH1^s8#(+K)$)Kd%kFQ}&y^fRcZ6!c$F zPa)`MQBN-D=TJ{3=;u*SD(DwbPa^0SQBN%BzoDK;&@Z8$P|z=R&8UJaYnT2eTa7MoHlN#RjiWJ)b1 zML=nxDYcLk5v2vD)Lc>|l;)dKGf9zAnrBK)B}GALt|>K<6cwd8rqozcG?ZqWQX@&x zQTp4I8cK?R(qE?3KvGPUW|>lbNwHA+)0FB-ijC4Arc_r_9F%@Hr8<)0qV$_7)s_?w zrC&{{mZbP7%`~N&k`kcwiz(HRln|w#O{u!1L@51aO4TGKMrnpARh5(krRkRP6DX*kFD7|M&c_igU>0MLGEh!&LlT0a>r2HsNG^L!93ZOK>lyXQah|+jd z$}Xu8O5;o^o20@h>0$ia6{bh|StS)gY0O(EjQa&yBo#$zv?*nlR1Bq2rj$uiag;`y zQbtK7P|_~R+ZCpXXOL79r4etPFit$Zq*5piH>GrvN~1K)l+sEngVIn_N+YQ(N<&O3 zwWM+=4K}4zlFFkr$dpn_s({i!Q%WJJB1!{HDY>LdDD^j`WRfbQ)X$WXN~(fVUsFmV zsVYi+OewLXYAE$Kr9_gdqtwfk5=yFpQcqJ#AgLxwJxnRSq*^F-H>G%zYNOQ6l;TRN zgHl&hiX*8mN?lATwxoI}bvC6~lIo+>$&_MBYJgHlQ;H#}Axa%gDY~RaD781GXp$PE z)XtQmN@{{qTT_Z6sVPcrOewOYW+=5brAU&RqtwcjB1&q3QcF{cAgLuvElerAq*f?3 zH>GfrTBFp=ltLu6L8+-HrG6u+ElN#H>9wSGC^a^vSCZPJ^uK?F{D%w6Z_%k=O6q`8 zL-UwkNa~1E15WfkpQ@SmwA4-)? z>6WDaC@GA1yTWvSx+!S@N)_KaVSALH`i7)|C{-|}>yiecRNj=XNg9k&Ia9hSX$VSX zP3elHp(vFxrOT3rp;X$GE=dZ7{(nPL%9Jij8i7(tQ@SAO9h6F#(s@ZEQ3}0_{AY#f z-f~XTD3pr5b;5XWIV)*2N<~fSjHEFr6)~mLlE$J`*pyC58i!ILQ#vVWJW2&k>4c;S zC>1cJ>0Olan$i(T@1c~(lnzUJAEn%;bV$+%DCIJxgOWZ( zDW@qNkn|BsIZSE4q>oX`Zc6(keS%UpQ`#%(Q^c6}OOliBM$ta~arEQYFMk$>sZI$#5N@-1Li==N+N@Gf!C4Gld zYE#-IX$nfIOlhN}sVJp1r45p%p_Iau)=T;xrR1ixPSOu3B{QY9l72)fsVS|IG##ZR zrnFkp43rX^(ke+mp_Is!R!aIArG%!mLeeiNB`~Gsl4hb5-;|a~`W2;krnFSjZz#nz zr6rPnM=6deEtd2LO0i98k)%ISie*X*CCx%9rYS9u^cPAoOliKPzfp>AO7kSmMk$&p z&6P9Q~FEN0+b?}(kw{}QHo$ne@a?}Qg~DP zL(*cD!kNzh(o&MLz4@04({9MGl9r+L+LUHWT8`2yQ~E{H3Y1=& z($A7sqV&R)ev-5brRSzJL(*!Lo|)2gNo!DgYDzy!T8q*XQ~E*DI+Pxp()W_qqx8s> zrb*g>(nC|4DrqB14@_x_q)jN@H>K|+ZAR&yDSazx3rcrQ=^IH~QMzMFUrXAC(rr_k zENMGRw@m3PNjp%wX-Z#8+KJK)Q~E;EE|jjD(&v(Pqjb%bK9jTurK_g&sieIqT`{Fk zB<(}#vMGHmX+KJrOz9&@2T;0bN*_u(h|&d9`asell+K&d`;rc$bk3CClXL{7v!?W} zq@yUEF{Me8j-hnglqO0#j?yVpnjq-}N+(Teyrh#ToiL?wl1`y?+?2*jI*rmXQyL@b z3`$2$X|$xXC>=4SQIgJ~bl8+eN;;3yAyaxs(glk zrG2I}RMHic_L|ZVNmo(YV@iW1T|;TNDGicz9i?5SG*HqFly;iZ07*Ad+F?rlCEY@4 zyD9aPbQ`5@rqox`9hA13QXffoQQBfky(Qg4X|pNyl5`)XO{UaS(gTz>noDD^OnJ2w|BPlmZO-<>wq&z4!F{M|M@}kt(lwL~8hf*U`dLb!4 zN)1ivxugOpH87=Tk_w_!-;|z8Duhx!Q+gt)FiLez>9M3DDAh5gN0N%7RNIsuN-Bm@ zEmL|RsW?hCP3gX*5-8O$rF)V}qEy|K?n)|!QZ-Y$BdIh>RZZ!(q%tT~F{N9Q%A!=+ zlx|8Yhf*a|x*@4NN)=7%x}*vyRWPM%k}9H9-juFNs)SNGQ@SFlGD>Al>9V9MD3vj# zOOmRhRN9m-N~(rZDO0*2sX9s}P3gR(8Yq=8rE`*Mq7=Fj_Ma7&J+aqkCDlTy*jp!T zdt$H8NUDueQByiCsSZj-OzD)Qx+oPkrIV8Cp;X9}PDrYcQbAKXE~x=Z1x)Ffq=qQv zH>IPJ8ljZWl#WPhj8a}xIxMLPN_kA_kff$4m?l+Bd(NNSBzR#Vz7sSQe5Olg;-wkTybrJa)6p_Iv#c1UWEQbtqS zE~x`b8BA%Lq>d=1H>ItTI-!)#l(tCfj8a-t+AOIHN@+}KlccUFr8cFFlDeUk%9J)p z>W)%MQ(7;n2TCbSX`Q5=C?z+gwUTIVL2B8$sl$J;uj8a@vS}bV@N^wkSk))w0 z#Wtmdl7^ua%aj&KQj7x)O-xgoFKGlyF-&Qmq<2t?Zc1|{jYKJ$Db0~I3ZU%30j2P!^t+^qD1|en-y}^! z>0c;J&+2{stE6{HiuUGTDonc}GbO!;(rZ)tMbi5yy)vbrC4GR>OH=wu(uXL$Fr^ui zK0@iaDNUF3F-p%&=|@SQp!C#~evtGjN>5Dbdr6<6^w^Z9N%|b6N2WAY(ibQ_G^Ht$ zzC`JPDSapDE0pe=(zlW(qjb-dzLE4bN_S1^Yf0arbjOq?OZpb2+otrDr0-C=WlCR4 znu5|zQ~E;ERFrO*(&v(

*ApK9lr4O4m&3Q%OIdbk&qTk@O=DdSB8nD4jQ@_ax0k>6|IOE9qC1&YIFBNxz|V#*`*X z`W>ayrZhp)A1IwNrSX#fMCqg{jgvGBr4yz!R?=T69XF*hlKw{Nm?@2xG#jO(rZh^@ z9F&fj(nv{jQ95i&??{@5(jikCA!$BJ2Tf_Xqy;D)Fr{IV7NWG@l!i)Lgwj4!8X{>i zN_$Odu%sm@?J=c6l9r;h+mr@MT87dtQyL&?IZ8WCslTKZDD5z%ev($AwB3~YN?L`| zHdE>&X*Eh)O{uq}H7IQ{rCyTOqO{qRdP-V{(k4^tA!$8I8%?RZqzx!-Fr{viHlnoN zl)6gVgwi@w>LO_~N^4E2v!pF3tuduelD49>+LSs<+J@39Q|cgTJ4!1}slB8fD6KH1 zc9M3YwA_^1O4^0eGE-_JX*WtsO{uk{Jt!?PrB;&mqO{nQT1wi7(jrr8A!$EK3r(rH zqys1|Fr{Xa4x%*Ql$uI9gwi}yY9i?{N^?!Av7{p?%`v4$l8&M@+msqgI)>8Urqn>v zag_ctrTUUipft;r>Pb3@(x0YOSJEkz{xGFFl1`)ayD8O{bOxp0OsSTnvnc&)N;M^& zLusZd)sS=^rC&^`x}*yz{cK9rBwa-5CsV2_=@LpaOsR^b%P37ZrOJ}7p!B0DRg!cS zr5{YGqNHmmeQ!z?Bwa^onkki+bOWWSrc_SSO_ZjXQdvp2Q2Nf4%1FA6(zm8mTGAbq zzA>dzlJ27PwJDX9bPuJ;rc^@GeU!d3rQ(tvp!B6F6_fN3r7ujWsH8_IeQrucBt1sy zGgB%o=?O}ono=Q2Pf_~BlnP3EhSJBTR6x>mls+=0{E}Xv^r0!`lk^g$4@@bqq*o}t zZ%TP2y+-LhQ_3yr4NC8tQfU7aGJN>d9RKhCKLzQZ!l4wTe+rLMkp3wGN7Npy6r_Jjh*FULDG^FR`lrMw1?iuXpcJHkN{UjD z{wWzsLHeiUC0_Qjq>B9ZHwX^HXU5 zlpduZ{Zj^%g7i-rQ3}#OWkTtkIj7M6DKkoEO)0d0%7Rjm{wXU;LHeg`CJxqQy!Fp^iO$F3erF2L+Ow?@zDM$KT1LR zrvfMi>7NRs6r_JDgi?_HsW3`G`lli&1?iuPq7CXq<<=h(kAo#6xu(PM=41EQ~{+R{ZmDhg7i<7P+Dis zDYSp8jM7?D3hke&pcJHks)|yO{;3*DLHeiaD6KT-6xu)4Kq*N7R1>A;<}ro#Pqk1A z(m&NkDM7N>*6r_J@j8c&P zsR>F!`lqHS1?iufp%kQlYK~Hn{;35@LHehbCuAe`<|Vkp8I+Ny4_1?iuV{H~{;4}k)66-A_D?-f3erFIL}`k7OriZ#FO-7xPrXqJ(m(Y>AWA{{r$HzM>7NFp6r_I|f>MzFX(&oT`ln$i1?iuLqZFin z8i7)f{^=c*g7i-#Q3}#OjY26%|1=sUw|~l|bHNytCYfiIoRY?(G|`lDNE(OI1XIc` zX*^2fO(~nC2`G&-rL2-BqBPc&vPhbQ(il_9Ea_d8Mw?P5N$;UF%9JundLN~crj$X_ z2PnN`O6etih|&mCN+;(g0IRCh04b`kPWxNt03PXG%#VeT`CIQ%Wr98DaDoaJxbk7DUPHcQ0i(*u_gV8 zQWsN-C22ZJolPmGq!}o6GNl-jenP3EDMgp`GfEvyDVn5TP-<^VQ6IbN7NJznl%7ahj8a`wdMs%PN_9->k))+4)i$Mvl9r)V%ak5ST8>gpQ@Sr{1xhtc z>7JyOC{;J5yOLI+RLzv`NLr0jRa3exX$?wMOzD=SwJ23KrJIu0p;XC~Zb({>Qbkj` zE@=Zw6-?=xq>U(*H>InRHlb9`l&(nHj8a)sx-4l6N@YyxlBBIDl{Te|lD45#%9Jih z+Ky65Q#vnc2TCPO>71mUC>1xQvyyh9RLqplNZO53QByiCX%9+8OzD)Qy(kqnrIV8O zp;X9}PDt91QbAKXF6jVD1x)Ffq=P8sH>IPJ4xyCKl#WO`j8a}xIxOi3N_kA_kfft1 zC$l+Bd(NIH#DR#Vz7=?qF) zOlg;-vnXXYrJa(_p_Iv#c1SvpQbtqSF6jbF8BA%Lq>Ct}H>ItTE}@jpl(tB^j8a-t z+AQe`N@+}KlccLCr8cFFlCGhY%9J)px{gvxQ(7IVL z9-$P^l$J<(j8a@vS}f@aN^wkSk))?6#WtmdlAfUy%aj&KdX7>|Q<^X71xhhYX`ZB) fC`C7=xsqO?6wQ?8NP3M@R8yKQ=?zLzLPGurQ=Dm~ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/063_nat64stateful_multimodule/003-expect.pcap b/autotest/units/001_one_port/063_nat64stateful_multimodule/003-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..456db472f85e86a4b2b2ef0c5994f43e870fdace GIT binary patch literal 227352 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 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/063_nat64stateful_multimodule/003-send.pcap b/autotest/units/001_one_port/063_nat64stateful_multimodule/003-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..6431f2f2ed21ef5e671aeb87880ca49e8ec31c05 GIT binary patch literal 288792 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 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/063_nat64stateful_multimodule/autotest.yaml b/autotest/units/001_one_port/063_nat64stateful_multimodule/autotest.yaml new file mode 100644 index 00000000..516a8242 --- /dev/null +++ b/autotest/units/001_one_port/063_nat64stateful_multimodule/autotest.yaml @@ -0,0 +1,15 @@ +steps: +- ipv4Update: "0.0.0.0/0 -> 200.0.0.1" +- ipv6Update: "::/0 -> fe80::1" +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap +- sendPackets: + - port: kni0 + send: 003-send.pcap + expect: 003-expect.pcap diff --git a/autotest/units/001_one_port/063_nat64stateful_multimodule/controlplane.conf b/autotest/units/001_one_port/063_nat64stateful_multimodule/controlplane.conf new file mode 100644 index 00000000..bff96eb2 --- /dev/null +++ b/autotest/units/001_one_port/063_nat64stateful_multimodule/controlplane.conf @@ -0,0 +1,78 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "nextModules": [ + "nat0", + "nat1", + "nat2" + ] + }, + "nat0": { + "type": "nat64stateful", + "ipv6_prefixes": [ + "2000:9999::/96" + ], + "ipv4_prefixes": [ + "122.122.122.122" + ], + "dscpMarkType": "never", + "nextModule": "vrf0" + }, + "nat1": { + "type": "nat64stateful", + "ipv6_prefixes": [ + "2000:2345::/96" + ], + "ipv4_prefixes": [ + "122.122.154.0/24" + ], + "dscpMarkType": "onlyDefault", + "dscp": 10, + "nextModule": "vrf0" + }, + "nat2": { + "type": "nat64stateful", + "ipv6_prefixes": [ + "2000:abcd::/96" + ], + "ipv4_prefixes": [ + "122.122.155.0/25" + ], + "dscpMarkType": "always", + "dscp": 20, + "nextModule": "vrf0" + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv6Prefix": "fe80::2/64", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/063_nat64stateful_multimodule/gen.py b/autotest/units/001_one_port/063_nat64stateful_multimodule/gen.py new file mode 100755 index 00000000..13a4f646 --- /dev/null +++ b/autotest/units/001_one_port/063_nat64stateful_multimodule/gen.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * + + +def write_pcap(filename, *packetsList): + if len(packetsList) == 0: + PcapWriter(filename)._write_header(Ether()) + return + + PcapWriter(filename) + + for packets in packetsList: + if type(packets) == list: + for packet in packets: + packet.time = 0 + wrpcap(filename, [p for p in packet], append=True) + else: + packets.time = 0 + wrpcap(filename, [p for p in packets], append=True) + + +# check lan (ipv6 -> ipv4). create state, check source ip +write_pcap("001-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:9999::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:9999::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0x4, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:9999::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0x80, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:9999::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0xfc, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:9999::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0xff, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:2345::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:2345::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0x4, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:2345::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0x80, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:2345::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0xfc, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:2345::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0xff, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:abcd::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:abcd::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0x4, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:abcd::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0x80, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:abcd::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0xfc, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:abcd::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0xff, hlim=64)/TCP(dport=443, sport=2048)) + +write_pcap("001-expect.pcap", + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.122.122", ttl=63, id=0, tos=0)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.122.122", ttl=63, id=0, tos=0x4)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.122.122", ttl=63, id=0, tos=0x80)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.122.122", ttl=63, id=0, tos=0xfc)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.122.122", ttl=63, id=0, tos=0xff)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.154.171", ttl=63, id=0, tos=0x28)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.154.171", ttl=63, id=0, tos=0x4)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.154.171", ttl=63, id=0, tos=0x80)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.154.171", ttl=63, id=0, tos=0xfc)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.154.171", ttl=63, id=0, tos=0xff)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.155.43", ttl=63, id=0, tos=0x50)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.155.43", ttl=63, id=0, tos=0x50)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.155.43", ttl=63, id=0, tos=0x50)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.155.43", ttl=63, id=0, tos=0x50)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.155.43", ttl=63, id=0, tos=0x53)/TCP(dport=443, sport=2048)) + + +# check wan (ipv4 -> ipv6) +write_pcap("002-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="122.122.122.122", src="102.124.0.0/24", ttl=64)/TCP(dport=2048, sport=443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="122.122.154.171", src="102.124.0.0/24", ttl=64)/TCP(dport=2048, sport=443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="122.122.155.43", src="102.124.0.0/24", ttl=64)/TCP(dport=2048, sport=443)) + +write_pcap("002-expect.pcap", + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", src="2000:9999::102.124.0.0/120", hlim=63, fl=0)/TCP(dport=2048, sport=443), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", src="2000:2345::102.124.0.0/120", hlim=63, fl=0)/TCP(dport=2048, sport=443), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", src="2000:abcd::102.124.0.0/120", hlim=63, fl=0)/TCP(dport=2048, sport=443)) + + +# check lan (ipv6 -> ipv4). create state, check source ip, check source port (1024 .. 65535) +write_pcap("003-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:9999::142.199.99.99", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb/118", tc=0x50, hlim=64)/TCP(dport=443, sport=4444), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:2345::142.199.99.99", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb/118", tc=0x50, hlim=64)/TCP(dport=443, sport=4444), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:abcd::142.199.99.99", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb/118", tc=0x50, hlim=64)/TCP(dport=443, sport=4444)) + +# 003-expect.pcap - dumped diff --git a/autotest/units/001_one_port/064_nat64stateful_egresstunnel/001-expect.pcap b/autotest/units/001_one_port/064_nat64stateful_egresstunnel/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..184f6e5b48e5ed9e3a322b1b59a52db157f5bafd GIT binary patch literal 616 zcmca|c+)~A1{MYw`2U}Qff2?5(pFFm7Gh)&R5Er6ZDe3b;b3rOV9)@G+Os)i&73*& z1PcobBL@RR09YlE2w+lR@X>+sh%_k^Y7!F%1LJO(UXV#%2VgujlbGOcI)UP*45&%W a7;e(SVG=Iir9(|(!En<)5=|Px;RFC`s79gy literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/064_nat64stateful_egresstunnel/001-send.pcap b/autotest/units/001_one_port/064_nat64stateful_egresstunnel/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..c54cbf384ef4c0733f7e62916882db36a34d7f0a GIT binary patch literal 776 zcmca|c+)~A1{MYw`2U}Qff2?5(tc3PAgE;Q5(<`JY-C_aX}g;M;)t+0fG7k2>P`7S z8^&j0VPWK8UiS?jDwxj1!N9m1W**4&S|u2d3Z^q-xV?vprn6wUU4e?G PkA^!mFfmdj)^G;^k#R`y literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/064_nat64stateful_egresstunnel/002-expect.pcap b/autotest/units/001_one_port/064_nat64stateful_egresstunnel/002-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..c0fded8adaad4029232885f180a7cfd01a95c9bc GIT binary patch literal 1296 zcmca|c+)~A1{MYw`2U}Qff2?5(os+h7Gh!$R5Er6ZDe3L!NK6lz~BKAbr3ut!DYn2 z7!eV{baS`lYX%dbpf}@xpu7f1-k!}pZ|2OICxE6haxgFifW$x`fJuQN*Z{%?k)+vl z-W#h;xlo&!I2agr!^{TR6nF&2L$iqy?xz&&emZ;$t4%pjo0u{Dq=&;MT%jik4L!!| zl2Dsm4kCwMHq<5-3_l$r(WcROf(95k?G1c9;Yxe(6mh!)Yl_H%rU+Jyw5Nk3MG&;< yYz0=EGNCrHVWhnSIBX)A$`8K8YEuT(CUy)zX_0Hw^SxMYN{8CSf#Iip3=9Bu-@~c^ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/064_nat64stateful_egresstunnel/002-send.pcap b/autotest/units/001_one_port/064_nat64stateful_egresstunnel/002-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..174fd0b43be7fcc5fd78ac4901deddd36689a93f GIT binary patch literal 1152 zcmca|c+)~A1{MYw`2U}Qff2?5(tc3PAgE;Q5(<`JY-C_aX}g;M;)t+0fG8xu$dK}X zHjEE6iIIbWApph?U{YXcn+W5PVLB6<=}a69jJsjxflO~zf$_*Nof*w^W(>FYQeZj@ zn&~VUZdV}EbViznJ2um)7w*_hr(U>YGo7~K&WaYRtQcvglY&@fLo=NXBhAQAU^+XR W>FgM8Z>7L=4m8s_Fx)P|zyJWHp=$U5 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/064_nat64stateful_egresstunnel/autotest.yaml b/autotest/units/001_one_port/064_nat64stateful_egresstunnel/autotest.yaml new file mode 100644 index 00000000..624901cd --- /dev/null +++ b/autotest/units/001_one_port/064_nat64stateful_egresstunnel/autotest.yaml @@ -0,0 +1,127 @@ +steps: +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 0.0.0.0 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 88.88.88.1 + prefix: 1.0.0.0/24 + path_information: 88.88.88.1:10001 + labels: + - 1100 + - nexthop: 88.88.88.2 + prefix: 1.0.0.0/24 + path_information: 88.88.88.2:10001 + labels: + - 1200 + - table_name: ipv4 mpls-vpn + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 88.88.88.1 + prefix: 1.0.0.254/32 + path_information: 88.88.88.1:11000 + labels: + - 1100 + - nexthop: 88.88.88.2 + prefix: 1.0.0.254/32 + path_information: 88.88.88.2:11001 + labels: + - 1200 + - table_name: ipv6 mpls-vpn + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 8888::1 + prefix: 7e57::/64 + path_information: 88.88.88.1:10001 + labels: + - 1100 + - nexthop: 8888::2 + prefix: 7e57::/64 + path_information: 88.88.88.2:10001 + labels: + - 1200 + - nexthop: 8888::1 + prefix: 7e57::fffe/128 + path_information: 88.88.88.1:9999 + labels: + - 1100 + - nexthop: 8888::2 + prefix: 7e57::fffe/128 + path_information: 88.88.88.2:15000 + labels: + - 1200 + - table_name: ipv4 mpls-vpn + peer: 0.0.0.0 + med: 0 + large_communities: + - 13238:1:0 + prefixes: + - nexthop: 88.88.88.1 + prefix: 1.0.0.253/32 + path_information: 88.88.88.1:10001 + labels: + - 1100 + - nexthop: 88.88.88.2 + prefix: 1.0.0.253/32 + path_information: 88.88.88.2:10001 + labels: + - 1200 + - table_name: ipv4 mpls-vpn + peer: 0.0.0.0 + med: 0 + prefixes: + - nexthop: 88.88.88.1 + prefix: 1.0.0.252/32 + path_information: 88.88.88.1:10001 + labels: + - 1100 + - nexthop: 88.88.88.2 + prefix: 1.0.0.252/32 + path_information: 88.88.88.2:10001 + labels: + - 1200 + - table_name: ipv6 mpls-vpn + large_communities: + - 13238:1:0 + prefixes: + - nexthop: 8888::1 + prefix: 7e57::fffd/128 + path_information: 88.88.88.1:10001 + labels: + - 1100 + - nexthop: 8888::2 + prefix: 7e57::fffd/128 + path_information: 88.88.88.2:10001 + labels: + - 1200 + - table_name: ipv6 mpls-vpn + prefixes: + - nexthop: 8888::1 + prefix: 7e57::fffc/128 + path_information: 88.88.88.1:10001 + labels: + - 1100 + - nexthop: 8888::2 + prefix: 7e57::fffc/128 + path_information: 88.88.88.2:10001 + labels: + - 1200 +- ipv4Update: + - "0.0.0.0/0 -> 100.0.0.1 200.0.0.1" +- ipv6Update: + - "::/0 -> c0de::100:1 c0de::200:1" +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap diff --git a/autotest/units/001_one_port/064_nat64stateful_egresstunnel/controlplane.conf b/autotest/units/001_one_port/064_nat64stateful_egresstunnel/controlplane.conf new file mode 100644 index 00000000..42699fef --- /dev/null +++ b/autotest/units/001_one_port/064_nat64stateful_egresstunnel/controlplane.conf @@ -0,0 +1,67 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "nextModules": [ + "nat0" + ] + }, + "nat0": { + "type": "nat64stateful", + "ipv6_prefixes": [ + "64:ff9b::/96" + ], + "ipv4_prefixes": [ + "153.153.153.200" + ], + "announces" : [ + "64:ff9b::/96", + "153.153.153.200" + ], + "nextModule": "route0:tunnel" + }, + "route0": { + "type": "route", + "ipv4SourceAddress": "10.50.0.1", + "ipv6SourceAddress": "2222:ddd:0:2266:aeae:ffff:feb0:abcd", + "udpDestinationPort": 6635, + "interfaces": { + "kni0.100": { + "neighborIPv4Address": "100.0.0.1", + "neighborIPv6Address": "c0de::100:1", + "neighborMacAddress": "00:00:00:00:00:01", + "nextModule": "lp0.100" + }, + "kni0.200": { + "neighborIPv4Address": "200.0.0.1", + "neighborIPv6Address": "c0de::200:1", + "neighborMacAddress": "00:00:00:00:00:02", + "nextModule": "lp0.200" + } + }, + "localPrefixes": [ + "1.0.0.255/32", + "7e57::ffff/128" + ], + "peers": { + "1": "A", + "2": "B", + "3": "C" + } + } + } +} diff --git a/autotest/units/001_one_port/064_nat64stateful_egresstunnel/gen.py b/autotest/units/001_one_port/064_nat64stateful_egresstunnel/gen.py new file mode 100755 index 00000000..091c482a --- /dev/null +++ b/autotest/units/001_one_port/064_nat64stateful_egresstunnel/gen.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * +from scapy.contrib.mpls import MPLS + + +def write_pcap(filename, *packetsList): + if len(packetsList) == 0: + PcapWriter(filename)._write_header(Ether()) + return + + PcapWriter(filename) + + for packets in packetsList: + if type(packets) == list: + for packet in packets: + packet.time = 0 + wrpcap(filename, [p for p in packet], append=True) + else: + packets.time = 0 + wrpcap(filename, [p for p in packets], append=True) + + +# check lan (ipv6 -> ipv4). local prefixes +write_pcap("001-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::4.4.4.1", src="::100", hlim=64)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::4.4.4.2", src="::100", hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::4.4.4.3", src="::100", hlim=64)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::4.4.4.4", src="::100", hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::4.4.4.1", src="::100", hlim=64)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::4.4.4.2", src="::100", hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::4.4.4.3", src="::100", hlim=64)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::4.4.4.4", src="::100", hlim=64)/TCP(dport=443, sport=2048)) + +write_pcap("001-expect.pcap", + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="4.4.4.1", src="153.153.153.200", ttl=63, id=0)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="4.4.4.2", src="153.153.153.200", ttl=63, id=0)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="4.4.4.3", src="153.153.153.200", ttl=63, id=0)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="4.4.4.4", src="153.153.153.200", ttl=63, id=0)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="4.4.4.1", src="153.153.153.200", ttl=63, id=0)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="4.4.4.2", src="153.153.153.200", ttl=63, id=0)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="4.4.4.3", src="153.153.153.200", ttl=63, id=0)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="4.4.4.4", src="153.153.153.200", ttl=63, id=0)/TCP(dport=443, sport=2048)) + + +# check lan (ipv6 -> ipv4). tunnel +write_pcap("002-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::1.0.0.1", src="::1", hlim=64)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::1.0.0.2", src="::2", hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::1.0.0.3", src="::3", hlim=64)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::1.0.0.4", src="::4", hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::1.0.0.1", src="::1", hlim=64, fl=1)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::1.0.0.2", src="::2", hlim=64, fl=1)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::1.0.0.3", src="::3", hlim=64, fl=1)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::1.0.0.4", src="::4", hlim=64, fl=1)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::1.0.0.5", src="::5", hlim=64, fl=1)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::1.0.0.6", src="::6", hlim=64, fl=1)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::1.0.0.7", src="::7", hlim=64, fl=1)/TCP(dport=80, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="64:ff9b::1.0.0.8", src="::8", hlim=64, fl=1)/TCP(dport=443, sport=2048)) + + +write_pcap("002-expect.pcap", + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="88.88.88.2", src="10.50.0.1", ttl=64, id=0)/UDP(dport=6635, sport=0xd9bb | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.1", src="153.153.153.200", ttl=63, id=0)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="88.88.88.2", src="10.50.0.1", ttl=64, id=0)/UDP(dport=6635, sport=0xcf4b | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.2", src="153.153.153.200", ttl=63, id=0)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.2", src="10.50.0.1", ttl=64, id=0)/UDP(dport=6635, sport=0xc3da | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.3", src="153.153.153.200", ttl=63, id=0)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64, id=0)/UDP(dport=6635, sport=0xd719 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.4", src="153.153.153.200", ttl=63, id=0)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="88.88.88.2", src="10.50.0.1", ttl=64, id=0)/UDP(dport=6635, sport=0xd9bb | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.1", src="153.153.153.200", ttl=63, id=0)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="88.88.88.2", src="10.50.0.1", ttl=64, id=0)/UDP(dport=6635, sport=0xcf4b | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.2", src="153.153.153.200", ttl=63, id=0)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.2", src="10.50.0.1", ttl=64, id=0)/UDP(dport=6635, sport=0xc3da | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.3", src="153.153.153.200", ttl=63, id=0)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64, id=0)/UDP(dport=6635, sport=0xd719 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.4", src="153.153.153.200", ttl=63, id=0)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64, id=0)/UDP(dport=6635, sport=0xdb88 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.5", src="153.153.153.200", ttl=63, id=0)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64, id=0)/UDP(dport=6635, sport=0xcd78 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.6", src="153.153.153.200", ttl=63, id=0)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64, id=0)/UDP(dport=6635, sport=0xc1e9 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.7", src="153.153.153.200", ttl=63, id=0)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64, id=0)/UDP(dport=6635, sport=0xe7bd | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.8", src="153.153.153.200", ttl=63, id=0)/TCP(dport=443, sport=2048))