8 from hashlib import blake2s
9 from scapy.packet import Packet
10 from scapy.packet import Raw
11 from scapy.layers.l2 import Ether, ARP
12 from scapy.layers.inet import IP, UDP
13 from scapy.layers.inet6 import IPv6
14 from scapy.contrib.wireguard import (
21 from cryptography.hazmat.primitives.asymmetric.x25519 import (
25 from cryptography.hazmat.primitives.serialization import (
31 from cryptography.hazmat.primitives.hashes import BLAKE2s, Hash
32 from cryptography.hazmat.primitives.hmac import HMAC
33 from cryptography.hazmat.backends import default_backend
34 from noise.connection import NoiseConnection, Keypair
36 from Crypto.Cipher import ChaCha20_Poly1305
37 from Crypto.Random import get_random_bytes
39 from vpp_ipip_tun_interface import VppIpIpTunInterface
40 from vpp_interface import VppInterface
41 from vpp_ip_route import VppIpRoute, VppRoutePath
42 from vpp_object import VppObject
43 from vpp_papi import VppEnum
44 from framework import VppTestCase
45 from re import compile
48 """ TestWg is a subclass of VPPTestCase classes.
55 def private_key_bytes(k):
56 return k.private_bytes(Encoding.Raw, PrivateFormat.Raw, NoEncryption())
59 def public_key_bytes(k):
60 return k.public_bytes(Encoding.Raw, PublicFormat.Raw)
63 def get_field_bytes(pkt, name):
64 fld, val = pkt.getfield_and_val(name)
65 return fld.i2m(pkt, val)
68 class VppWgInterface(VppInterface):
70 VPP WireGuard interface
73 def __init__(self, test, src, port):
74 super(VppWgInterface, self).__init__(test)
78 self.private_key = X25519PrivateKey.generate()
79 self.public_key = self.private_key.public_key()
81 def public_key_bytes(self):
82 return public_key_bytes(self.public_key)
84 def private_key_bytes(self):
85 return private_key_bytes(self.private_key)
87 def add_vpp_config(self):
88 r = self.test.vapi.wireguard_interface_create(
90 "user_instance": 0xFFFFFFFF,
93 "private_key": private_key_bytes(self.private_key),
94 "generate_key": False,
97 self.set_sw_if_index(r.sw_if_index)
98 self.test.registry.register(self, self.test.logger)
101 def remove_vpp_config(self):
102 self.test.vapi.wireguard_interface_delete(sw_if_index=self._sw_if_index)
104 def query_vpp_config(self):
105 ts = self.test.vapi.wireguard_interface_dump(sw_if_index=0xFFFFFFFF)
108 t.interface.sw_if_index == self._sw_if_index
109 and str(t.interface.src_ip) == self.src
110 and t.interface.port == self.port
111 and t.interface.private_key == private_key_bytes(self.private_key)
116 def want_events(self, peer_index=0xFFFFFFFF):
117 self.test.vapi.want_wireguard_peer_events(
120 sw_if_index=self._sw_if_index,
121 peer_index=peer_index,
124 def wait_events(self, expect, peers, timeout=5):
125 for i in range(len(peers)):
126 rv = self.test.vapi.wait_for_event(timeout, "wireguard_peer_event")
127 self.test.assertEqual(rv.peer_index, peers[i])
128 self.test.assertEqual(rv.flags, expect)
131 return self.object_id()
134 return "wireguard-%d" % self._sw_if_index
137 def find_route(test, prefix, is_ip6, table_id=0):
138 routes = test.vapi.ip_route_dump(table_id, is_ip6)
141 if table_id == e.route.table_id and str(e.route.prefix) == str(prefix):
146 NOISE_HANDSHAKE_NAME = b"Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"
147 NOISE_IDENTIFIER_NAME = b"WireGuard v1 zx2c4 Jason@zx2c4.com"
150 class VppWgPeer(VppObject):
151 def __init__(self, test, itf, endpoint, port, allowed_ips, persistent_keepalive=15):
154 self.endpoint = endpoint
156 self.allowed_ips = allowed_ips
157 self.persistent_keepalive = persistent_keepalive
159 # remote peer's public
160 self.private_key = X25519PrivateKey.generate()
161 self.public_key = self.private_key.public_key()
163 # cookie related params
164 self.cookie_key = blake2s(b"cookie--" + self.public_key_bytes()).digest()
165 self.last_sent_cookie = None
167 self.noise = NoiseConnection.from_name(NOISE_HANDSHAKE_NAME)
169 def add_vpp_config(self, is_ip6=False):
170 rv = self._test.vapi.wireguard_peer_add(
172 "public_key": self.public_key_bytes(),
174 "endpoint": self.endpoint,
175 "n_allowed_ips": len(self.allowed_ips),
176 "allowed_ips": self.allowed_ips,
177 "sw_if_index": self.itf.sw_if_index,
178 "persistent_keepalive": self.persistent_keepalive,
181 self.index = rv.peer_index
182 self.receiver_index = self.index + 1
183 self._test.registry.register(self, self._test.logger)
186 def remove_vpp_config(self):
187 self._test.vapi.wireguard_peer_remove(peer_index=self.index)
190 return "wireguard-peer-%s" % self.index
192 def public_key_bytes(self):
193 return public_key_bytes(self.public_key)
195 def query_vpp_config(self):
196 peers = self._test.vapi.wireguard_peers_dump()
200 p.peer.public_key == self.public_key_bytes()
201 and p.peer.port == self.port
202 and str(p.peer.endpoint) == self.endpoint
203 and p.peer.sw_if_index == self.itf.sw_if_index
204 and len(self.allowed_ips) == p.peer.n_allowed_ips
206 self.allowed_ips.sort()
207 p.peer.allowed_ips.sort()
209 for (a1, a2) in zip(self.allowed_ips, p.peer.allowed_ips):
210 if str(a1) != str(a2):
215 def mk_tunnel_header(self, tx_itf, is_ip6=False):
218 Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac)
219 / IP(src=self.endpoint, dst=self.itf.src)
220 / UDP(sport=self.port, dport=self.itf.port)
224 Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac)
225 / IPv6(src=self.endpoint, dst=self.itf.src)
226 / UDP(sport=self.port, dport=self.itf.port)
229 def noise_init(self, public_key=None):
230 self.noise.set_prologue(NOISE_IDENTIFIER_NAME)
231 self.noise.set_psks(psk=bytes(bytearray(32)))
234 public_key = self.itf.public_key
237 self.noise.set_keypair_from_private_bytes(
238 Keypair.STATIC, private_key_bytes(self.private_key)
241 self.noise.set_keypair_from_public_bytes(
242 Keypair.REMOTE_STATIC, public_key_bytes(public_key)
245 self.noise.start_handshake()
247 def mk_cookie(self, p, tx_itf, is_resp=False, is_ip6=False):
248 self.verify_header(p, is_ip6)
250 wg_pkt = Wireguard(p[Raw])
253 self._test.assertEqual(wg_pkt[Wireguard].message_type, 2)
254 self._test.assertEqual(wg_pkt[Wireguard].reserved_zero, 0)
255 self._test.assertEqual(wg_pkt[WireguardResponse].mac2, bytes([0] * 16))
257 self._test.assertEqual(wg_pkt[Wireguard].message_type, 1)
258 self._test.assertEqual(wg_pkt[Wireguard].reserved_zero, 0)
259 self._test.assertEqual(wg_pkt[WireguardInitiation].mac2, bytes([0] * 16))
261 # collect info from wg packet (initiation or response)
262 src = get_field_bytes(p[IPv6 if is_ip6 else IP], "src")
263 sport = p[UDP].sport.to_bytes(2, byteorder="big")
265 mac1 = wg_pkt[WireguardResponse].mac1
266 sender_index = wg_pkt[WireguardResponse].sender_index
268 mac1 = wg_pkt[WireguardInitiation].mac1
269 sender_index = wg_pkt[WireguardInitiation].sender_index
272 cookie_reply = Wireguard() / WireguardCookieReply()
273 cookie_reply[Wireguard].message_type = 3
274 cookie_reply[Wireguard].reserved_zero = 0
275 cookie_reply[WireguardCookieReply].receiver_index = sender_index
276 nonce = get_random_bytes(24)
277 cookie_reply[WireguardCookieReply].nonce = nonce
279 # generate cookie data
280 changing_secret = get_random_bytes(32)
281 self.last_sent_cookie = blake2s(
282 src + sport, digest_size=16, key=changing_secret
285 # encrypt cookie data
286 cipher = ChaCha20_Poly1305.new(key=self.cookie_key, nonce=nonce)
288 ciphertext, tag = cipher.encrypt_and_digest(self.last_sent_cookie)
289 cookie_reply[WireguardCookieReply].encrypted_cookie = ciphertext + tag
291 # prepare cookie reply to be sent
292 cookie_reply = self.mk_tunnel_header(tx_itf, is_ip6) / cookie_reply
296 def mk_handshake(self, tx_itf, is_ip6=False, public_key=None):
297 self.noise.set_as_initiator()
298 self.noise_init(public_key)
300 p = Wireguard() / WireguardInitiation()
302 p[Wireguard].message_type = 1
303 p[Wireguard].reserved_zero = 0
304 p[WireguardInitiation].sender_index = self.receiver_index
306 # some random data for the message
307 # lifted from the noise protocol's wireguard example
308 now = datetime.datetime.now()
311 4611686018427387914 + int(now.timestamp()),
312 int(now.microsecond * 1e3),
314 b = self.noise.write_message(payload=tai)
316 # load noise into init message
317 p[WireguardInitiation].unencrypted_ephemeral = b[0:32]
318 p[WireguardInitiation].encrypted_static = b[32:80]
319 p[WireguardInitiation].encrypted_timestamp = b[80:108]
321 # generate the mac1 hash
322 mac_key = blake2s(b"mac1----" + self.itf.public_key_bytes()).digest()
323 p[WireguardInitiation].mac1 = blake2s(
324 bytes(p)[0:116], digest_size=16, key=mac_key
326 p[WireguardInitiation].mac2 = bytearray(16)
328 p = self.mk_tunnel_header(tx_itf, is_ip6) / p
332 def verify_header(self, p, is_ip6=False):
334 self._test.assertEqual(p[IP].src, self.itf.src)
335 self._test.assertEqual(p[IP].dst, self.endpoint)
337 self._test.assertEqual(p[IPv6].src, self.itf.src)
338 self._test.assertEqual(p[IPv6].dst, self.endpoint)
339 self._test.assertEqual(p[UDP].sport, self.itf.port)
340 self._test.assertEqual(p[UDP].dport, self.port)
341 self._test.assert_packet_checksums_valid(p)
343 def consume_init(self, p, tx_itf, is_ip6=False, is_mac2=False):
344 self.noise.set_as_responder()
345 self.noise_init(self.itf.public_key)
346 self.verify_header(p, is_ip6)
348 init = Wireguard(p[Raw])
350 self._test.assertEqual(init[Wireguard].message_type, 1)
351 self._test.assertEqual(init[Wireguard].reserved_zero, 0)
353 self.sender = init[WireguardInitiation].sender_index
355 # validate the mac1 hash
356 mac_key = blake2s(b"mac1----" + public_key_bytes(self.public_key)).digest()
357 mac1 = blake2s(bytes(init)[0:-32], digest_size=16, key=mac_key).digest()
358 self._test.assertEqual(init[WireguardInitiation].mac1, mac1)
360 # validate the mac2 hash
362 self._test.assertNotEqual(init[WireguardInitiation].mac2, bytes([0] * 16))
363 self._test.assertNotEqual(self.last_sent_cookie, None)
365 bytes(init)[0:-16], digest_size=16, key=self.last_sent_cookie
367 self._test.assertEqual(init[WireguardInitiation].mac2, mac2)
368 self.last_sent_cookie = None
370 self._test.assertEqual(init[WireguardInitiation].mac2, bytes([0] * 16))
372 # this passes only unencrypted_ephemeral, encrypted_static,
373 # encrypted_timestamp fields of the init
374 payload = self.noise.read_message(bytes(init)[8:-32])
377 b = self.noise.write_message()
378 mac_key = blake2s(b"mac1----" + public_key_bytes(self.itf.public_key)).digest()
379 resp = Wireguard(message_type=2, reserved_zero=0) / WireguardResponse(
380 sender_index=self.receiver_index,
381 receiver_index=self.sender,
382 unencrypted_ephemeral=b[0:32],
383 encrypted_nothing=b[32:],
385 mac1 = blake2s(bytes(resp)[:-32], digest_size=16, key=mac_key).digest()
386 resp[WireguardResponse].mac1 = mac1
388 resp = self.mk_tunnel_header(tx_itf, is_ip6) / resp
389 self._test.assertTrue(self.noise.handshake_finished)
393 def consume_response(self, p, is_ip6=False):
394 self.verify_header(p, is_ip6)
396 resp = Wireguard(p[Raw])
398 self._test.assertEqual(resp[Wireguard].message_type, 2)
399 self._test.assertEqual(resp[Wireguard].reserved_zero, 0)
400 self._test.assertEqual(
401 resp[WireguardResponse].receiver_index, self.receiver_index
404 self.sender = resp[Wireguard].sender_index
406 payload = self.noise.read_message(bytes(resp)[12:60])
407 self._test.assertEqual(payload, b"")
408 self._test.assertTrue(self.noise.handshake_finished)
410 def decrypt_transport(self, p, is_ip6=False):
411 self.verify_header(p, is_ip6)
413 p = Wireguard(p[Raw])
414 self._test.assertEqual(p[Wireguard].message_type, 4)
415 self._test.assertEqual(p[Wireguard].reserved_zero, 0)
416 self._test.assertEqual(
417 p[WireguardTransport].receiver_index, self.receiver_index
420 d = self.noise.decrypt(p[WireguardTransport].encrypted_encapsulated_packet)
423 def encrypt_transport(self, p):
424 return self.noise.encrypt(bytes(p))
426 def validate_encapped(self, rxs, tx, is_ip6=False):
429 rx = IP(self.decrypt_transport(rx))
431 # chech the oringial packet is present
432 self._test.assertEqual(rx[IP].dst, tx[IP].dst)
433 self._test.assertEqual(rx[IP].ttl, tx[IP].ttl - 1)
435 rx = IPv6(self.decrypt_transport(rx))
437 # chech the oringial packet is present
438 self._test.assertEqual(rx[IPv6].dst, tx[IPv6].dst)
439 self._test.assertEqual(rx[IPv6].ttl, tx[IPv6].ttl - 1)
441 def want_events(self):
442 self._test.vapi.want_wireguard_peer_events(
445 peer_index=self.index,
446 sw_if_index=self.itf.sw_if_index,
449 def wait_event(self, expect, timeout=5):
450 rv = self._test.vapi.wait_for_event(timeout, "wireguard_peer_event")
451 self._test.assertEqual(rv.flags, expect)
452 self._test.assertEqual(rv.peer_index, self.index)
455 class TestWg(VppTestCase):
456 """Wireguard Test Case"""
458 error_str = compile(r"Error")
460 wg4_output_node_name = "/err/wg4-output-tun/"
461 wg4_input_node_name = "/err/wg4-input/"
462 wg6_output_node_name = "/err/wg6-output-tun/"
463 wg6_input_node_name = "/err/wg6-input/"
464 kp4_error = wg4_output_node_name + "Keypair error"
465 mac4_error = wg4_input_node_name + "Invalid MAC handshake"
466 peer4_in_err = wg4_input_node_name + "Peer error"
467 peer4_out_err = wg4_output_node_name + "Peer error"
468 kp6_error = wg6_output_node_name + "Keypair error"
469 mac6_error = wg6_input_node_name + "Invalid MAC handshake"
470 peer6_in_err = wg6_input_node_name + "Peer error"
471 peer6_out_err = wg6_output_node_name + "Peer error"
472 cookie_dec4_err = wg4_input_node_name + "Failed during Cookie decryption"
473 cookie_dec6_err = wg6_input_node_name + "Failed during Cookie decryption"
477 super(TestWg, cls).setUpClass()
479 cls.create_pg_interfaces(range(3))
480 for i in cls.pg_interfaces:
488 super(TestWg, cls).tearDownClass()
492 def tearDownClass(cls):
493 super(TestWg, cls).tearDownClass()
496 super(VppTestCase, self).setUp()
497 self.base_kp4_err = self.statistics.get_err_counter(self.kp4_error)
498 self.base_mac4_err = self.statistics.get_err_counter(self.mac4_error)
499 self.base_peer4_in_err = self.statistics.get_err_counter(self.peer4_in_err)
500 self.base_peer4_out_err = self.statistics.get_err_counter(self.peer4_out_err)
501 self.base_kp6_err = self.statistics.get_err_counter(self.kp6_error)
502 self.base_mac6_err = self.statistics.get_err_counter(self.mac6_error)
503 self.base_peer6_in_err = self.statistics.get_err_counter(self.peer6_in_err)
504 self.base_peer6_out_err = self.statistics.get_err_counter(self.peer6_out_err)
505 self.base_cookie_dec4_err = self.statistics.get_err_counter(
508 self.base_cookie_dec6_err = self.statistics.get_err_counter(
512 def test_wg_interface(self):
513 """Simple interface creation"""
517 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
519 self.logger.info(self.vapi.cli("sh int"))
522 wg0.remove_vpp_config()
524 def test_handshake_hash(self):
525 """test hashing an init message"""
526 # a init packet generated by linux given the key below
549 b = bytearray.fromhex(h)
552 pubb = base64.b64decode("aRuHFTTxICIQNefp05oKWlJv3zgKxb8+WW7JJMh0jyM=")
553 pub = X25519PublicKey.from_public_bytes(pubb)
555 self.assertEqual(pubb, public_key_bytes(pub))
557 # strip the macs and build a new packet
559 mac_key = blake2s(b"mac1----" + public_key_bytes(pub)).digest()
560 init += blake2s(init, digest_size=16, key=mac_key).digest()
563 act = Wireguard(init)
565 self.assertEqual(tgt, act)
567 def _test_wg_send_cookie_tmpl(self, is_resp, is_ip6):
570 # create wg interface
572 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
576 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
580 self.pg_enable_capture(self.pg_interfaces)
586 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
590 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
592 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
595 # prepare and send a handshake initiation
596 # expect the peer to send a handshake response
597 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
598 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
600 # wait for the peer to send a handshake initiation
601 rxs = self.pg1.get_capture(1, timeout=2)
603 # prepare and send a wrong cookie reply
604 # expect no replies and the cookie error incremented
605 cookie = peer_1.mk_cookie(rxs[0], self.pg1, is_resp=is_resp, is_ip6=is_ip6)
606 cookie.nonce = b"1234567890"
607 self.send_and_assert_no_replies(self.pg1, [cookie], timeout=0.1)
610 self.base_cookie_dec6_err + 1,
611 self.statistics.get_err_counter(self.cookie_dec6_err),
615 self.base_cookie_dec4_err + 1,
616 self.statistics.get_err_counter(self.cookie_dec4_err),
619 # prepare and send a correct cookie reply
620 cookie = peer_1.mk_cookie(rxs[0], self.pg1, is_resp=is_resp, is_ip6=is_ip6)
621 self.pg_send(self.pg1, [cookie])
623 # wait for the peer to send a handshake initiation with mac2 set
624 rxs = self.pg1.get_capture(1, timeout=6)
626 # verify the initiation and its mac2
627 peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6, is_mac2=True)
630 peer_1.remove_vpp_config()
631 wg0.remove_vpp_config()
633 def test_wg_send_cookie_on_init_v4(self):
634 """Send cookie on handshake initiation (v4)"""
635 self._test_wg_send_cookie_tmpl(is_resp=False, is_ip6=False)
637 def test_wg_send_cookie_on_init_v6(self):
638 """Send cookie on handshake initiation (v6)"""
639 self._test_wg_send_cookie_tmpl(is_resp=False, is_ip6=True)
641 def test_wg_send_cookie_on_resp_v4(self):
642 """Send cookie on handshake response (v4)"""
643 self._test_wg_send_cookie_tmpl(is_resp=True, is_ip6=False)
645 def test_wg_send_cookie_on_resp_v6(self):
646 """Send cookie on handshake response (v6)"""
647 self._test_wg_send_cookie_tmpl(is_resp=True, is_ip6=True)
649 def test_wg_peer_resp(self):
650 """Send handshake response"""
654 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
658 self.pg_enable_capture(self.pg_interfaces)
662 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
664 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
667 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
670 # wait for the peer to send a handshake
671 rx = self.pg1.get_capture(1, timeout=2)
673 # consume the handshake in the noise protocol and
674 # generate the response
675 resp = peer_1.consume_init(rx[0], self.pg1)
677 # send the response, get keepalive
678 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
681 b = peer_1.decrypt_transport(rx)
682 self.assertEqual(0, len(b))
684 # send a packets that are routed into the tunnel
686 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
687 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
688 / UDP(sport=555, dport=556)
692 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
694 peer_1.validate_encapped(rxs, p)
696 # send packets into the tunnel, expect to receive them on
700 peer_1.mk_tunnel_header(self.pg1)
701 / Wireguard(message_type=4, reserved_zero=0)
702 / WireguardTransport(
703 receiver_index=peer_1.sender,
705 encrypted_encapsulated_packet=peer_1.encrypt_transport(
707 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
708 / UDP(sport=222, dport=223)
717 rxs = self.send_and_expect(self.pg1, p, self.pg0)
720 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
721 self.assertEqual(rx[IP].ttl, 19)
723 r1.remove_vpp_config()
724 peer_1.remove_vpp_config()
725 wg0.remove_vpp_config()
727 def test_wg_peer_v4o4(self):
733 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
738 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
740 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
743 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
746 self, "20.22.3.0", 24, [VppRoutePath("20.22.3.1", wg0.sw_if_index)]
749 # route a packet into the wg interface
750 # use the allowed-ip prefix
751 # this is dropped because the peer is not initiated
753 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
754 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
755 / UDP(sport=555, dport=556)
758 self.send_and_assert_no_replies(self.pg0, [p])
760 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
763 # route a packet into the wg interface
764 # use a not allowed-ip prefix
765 # this is dropped because there is no matching peer
767 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
768 / IP(src=self.pg0.remote_ip4, dst="20.22.3.2")
769 / UDP(sport=555, dport=556)
772 self.send_and_assert_no_replies(self.pg0, [p])
774 self.base_peer4_out_err + 1,
775 self.statistics.get_err_counter(self.peer4_out_err),
778 # send a handsake from the peer with an invalid MAC
779 p = peer_1.mk_handshake(self.pg1)
780 p[WireguardInitiation].mac1 = b"foobar"
781 self.send_and_assert_no_replies(self.pg1, [p])
783 self.base_mac4_err + 1, self.statistics.get_err_counter(self.mac4_error)
786 # send a handsake from the peer but signed by the wrong key.
787 p = peer_1.mk_handshake(
788 self.pg1, False, X25519PrivateKey.generate().public_key()
790 self.send_and_assert_no_replies(self.pg1, [p])
792 self.base_peer4_in_err + 1,
793 self.statistics.get_err_counter(self.peer4_in_err),
796 # send a valid handsake init for which we expect a response
797 p = peer_1.mk_handshake(self.pg1)
799 rx = self.send_and_expect(self.pg1, [p], self.pg1)
801 peer_1.consume_response(rx[0])
803 # route a packet into the wg interface
804 # this is dropped because the peer is still not initiated
806 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
807 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
808 / UDP(sport=555, dport=556)
811 self.send_and_assert_no_replies(self.pg0, [p])
813 self.base_kp4_err + 2, self.statistics.get_err_counter(self.kp4_error)
816 # send a data packet from the peer through the tunnel
817 # this completes the handshake
819 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
820 / UDP(sport=222, dport=223)
823 d = peer_1.encrypt_transport(p)
824 p = peer_1.mk_tunnel_header(self.pg1) / (
825 Wireguard(message_type=4, reserved_zero=0)
826 / WireguardTransport(
827 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
830 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
833 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
834 self.assertEqual(rx[IP].ttl, 19)
836 # send a packets that are routed into the tunnel
838 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
839 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
840 / UDP(sport=555, dport=556)
844 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
847 rx = IP(peer_1.decrypt_transport(rx))
849 # chech the oringial packet is present
850 self.assertEqual(rx[IP].dst, p[IP].dst)
851 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
853 # send packets into the tunnel, expect to receive them on
857 peer_1.mk_tunnel_header(self.pg1)
858 / Wireguard(message_type=4, reserved_zero=0)
859 / WireguardTransport(
860 receiver_index=peer_1.sender,
862 encrypted_encapsulated_packet=peer_1.encrypt_transport(
864 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
865 / UDP(sport=222, dport=223)
874 rxs = self.send_and_expect(self.pg1, p, self.pg0)
877 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
878 self.assertEqual(rx[IP].ttl, 19)
880 r1.remove_vpp_config()
881 r2.remove_vpp_config()
882 peer_1.remove_vpp_config()
883 wg0.remove_vpp_config()
885 def test_wg_peer_v6o6(self):
891 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
896 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
897 ).add_vpp_config(True)
898 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
901 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
904 self, "22::3:0", 112, [VppRoutePath("22::3:1", wg0.sw_if_index)]
907 # route a packet into the wg interface
908 # use the allowed-ip prefix
909 # this is dropped because the peer is not initiated
912 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
913 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
914 / UDP(sport=555, dport=556)
917 self.send_and_assert_no_replies(self.pg0, [p])
920 self.base_kp6_err + 1, self.statistics.get_err_counter(self.kp6_error)
923 # route a packet into the wg interface
924 # use a not allowed-ip prefix
925 # this is dropped because there is no matching peer
927 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
928 / IPv6(src=self.pg0.remote_ip6, dst="22::3:2")
929 / UDP(sport=555, dport=556)
932 self.send_and_assert_no_replies(self.pg0, [p])
934 self.base_peer6_out_err + 1,
935 self.statistics.get_err_counter(self.peer6_out_err),
938 # send a handsake from the peer with an invalid MAC
939 p = peer_1.mk_handshake(self.pg1, True)
940 p[WireguardInitiation].mac1 = b"foobar"
941 self.send_and_assert_no_replies(self.pg1, [p])
944 self.base_mac6_err + 1, self.statistics.get_err_counter(self.mac6_error)
947 # send a handsake from the peer but signed by the wrong key.
948 p = peer_1.mk_handshake(
949 self.pg1, True, X25519PrivateKey.generate().public_key()
951 self.send_and_assert_no_replies(self.pg1, [p])
953 self.base_peer6_in_err + 1,
954 self.statistics.get_err_counter(self.peer6_in_err),
957 # send a valid handsake init for which we expect a response
958 p = peer_1.mk_handshake(self.pg1, True)
960 rx = self.send_and_expect(self.pg1, [p], self.pg1)
962 peer_1.consume_response(rx[0], True)
964 # route a packet into the wg interface
965 # this is dropped because the peer is still not initiated
967 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
968 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
969 / UDP(sport=555, dport=556)
972 self.send_and_assert_no_replies(self.pg0, [p])
974 self.base_kp6_err + 2, self.statistics.get_err_counter(self.kp6_error)
977 # send a data packet from the peer through the tunnel
978 # this completes the handshake
980 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
981 / UDP(sport=222, dport=223)
984 d = peer_1.encrypt_transport(p)
985 p = peer_1.mk_tunnel_header(self.pg1, True) / (
986 Wireguard(message_type=4, reserved_zero=0)
987 / WireguardTransport(
988 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
991 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
994 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
995 self.assertEqual(rx[IPv6].hlim, 19)
997 # send a packets that are routed into the tunnel
999 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1000 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1001 / UDP(sport=555, dport=556)
1005 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1008 rx = IPv6(peer_1.decrypt_transport(rx, True))
1010 # chech the oringial packet is present
1011 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
1012 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim - 1)
1014 # send packets into the tunnel, expect to receive them on
1018 peer_1.mk_tunnel_header(self.pg1, True)
1019 / Wireguard(message_type=4, reserved_zero=0)
1020 / WireguardTransport(
1021 receiver_index=peer_1.sender,
1023 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1025 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1026 / UDP(sport=222, dport=223)
1032 for ii in range(255)
1035 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1038 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1039 self.assertEqual(rx[IPv6].hlim, 19)
1041 r1.remove_vpp_config()
1042 r2.remove_vpp_config()
1043 peer_1.remove_vpp_config()
1044 wg0.remove_vpp_config()
1046 def test_wg_peer_v6o4(self):
1052 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1057 self, wg0, self.pg1.remote_ip4, port + 1, ["1::3:0/112"]
1058 ).add_vpp_config(True)
1059 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1062 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
1065 # route a packet into the wg interface
1066 # use the allowed-ip prefix
1067 # this is dropped because the peer is not initiated
1069 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1070 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1071 / UDP(sport=555, dport=556)
1074 self.send_and_assert_no_replies(self.pg0, [p])
1076 self.base_kp6_err + 1, self.statistics.get_err_counter(self.kp6_error)
1079 # send a handsake from the peer with an invalid MAC
1080 p = peer_1.mk_handshake(self.pg1)
1081 p[WireguardInitiation].mac1 = b"foobar"
1082 self.send_and_assert_no_replies(self.pg1, [p])
1085 self.base_mac4_err + 1, self.statistics.get_err_counter(self.mac4_error)
1088 # send a handsake from the peer but signed by the wrong key.
1089 p = peer_1.mk_handshake(
1090 self.pg1, False, X25519PrivateKey.generate().public_key()
1092 self.send_and_assert_no_replies(self.pg1, [p])
1094 self.base_peer4_in_err + 1,
1095 self.statistics.get_err_counter(self.peer4_in_err),
1098 # send a valid handsake init for which we expect a response
1099 p = peer_1.mk_handshake(self.pg1)
1101 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1103 peer_1.consume_response(rx[0])
1105 # route a packet into the wg interface
1106 # this is dropped because the peer is still not initiated
1108 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1109 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1110 / UDP(sport=555, dport=556)
1113 self.send_and_assert_no_replies(self.pg0, [p])
1115 self.base_kp6_err + 2, self.statistics.get_err_counter(self.kp6_error)
1118 # send a data packet from the peer through the tunnel
1119 # this completes the handshake
1121 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1122 / UDP(sport=222, dport=223)
1125 d = peer_1.encrypt_transport(p)
1126 p = peer_1.mk_tunnel_header(self.pg1) / (
1127 Wireguard(message_type=4, reserved_zero=0)
1128 / WireguardTransport(
1129 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1132 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1135 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1136 self.assertEqual(rx[IPv6].hlim, 19)
1138 # send a packets that are routed into the tunnel
1140 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1141 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1142 / UDP(sport=555, dport=556)
1146 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1149 rx = IPv6(peer_1.decrypt_transport(rx))
1151 # chech the oringial packet is present
1152 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
1153 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim - 1)
1155 # send packets into the tunnel, expect to receive them on
1159 peer_1.mk_tunnel_header(self.pg1)
1160 / Wireguard(message_type=4, reserved_zero=0)
1161 / WireguardTransport(
1162 receiver_index=peer_1.sender,
1164 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1166 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1167 / UDP(sport=222, dport=223)
1173 for ii in range(255)
1176 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1179 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1180 self.assertEqual(rx[IPv6].hlim, 19)
1182 r1.remove_vpp_config()
1183 peer_1.remove_vpp_config()
1184 wg0.remove_vpp_config()
1186 def test_wg_peer_v4o6(self):
1192 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1197 self, wg0, self.pg1.remote_ip6, port + 1, ["10.11.3.0/24"]
1199 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1202 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1205 # route a packet into the wg interface
1206 # use the allowed-ip prefix
1207 # this is dropped because the peer is not initiated
1209 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1210 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1211 / UDP(sport=555, dport=556)
1214 self.send_and_assert_no_replies(self.pg0, [p])
1216 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
1219 # send a handsake from the peer with an invalid MAC
1220 p = peer_1.mk_handshake(self.pg1, True)
1221 p[WireguardInitiation].mac1 = b"foobar"
1222 self.send_and_assert_no_replies(self.pg1, [p])
1224 self.base_mac6_err + 1, self.statistics.get_err_counter(self.mac6_error)
1227 # send a handsake from the peer but signed by the wrong key.
1228 p = peer_1.mk_handshake(
1229 self.pg1, True, X25519PrivateKey.generate().public_key()
1231 self.send_and_assert_no_replies(self.pg1, [p])
1233 self.base_peer6_in_err + 1,
1234 self.statistics.get_err_counter(self.peer6_in_err),
1237 # send a valid handsake init for which we expect a response
1238 p = peer_1.mk_handshake(self.pg1, True)
1240 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1242 peer_1.consume_response(rx[0], True)
1244 # route a packet into the wg interface
1245 # this is dropped because the peer is still not initiated
1247 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1248 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1249 / UDP(sport=555, dport=556)
1252 self.send_and_assert_no_replies(self.pg0, [p])
1254 self.base_kp4_err + 2, self.statistics.get_err_counter(self.kp4_error)
1257 # send a data packet from the peer through the tunnel
1258 # this completes the handshake
1260 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1261 / UDP(sport=222, dport=223)
1264 d = peer_1.encrypt_transport(p)
1265 p = peer_1.mk_tunnel_header(self.pg1, True) / (
1266 Wireguard(message_type=4, reserved_zero=0)
1267 / WireguardTransport(
1268 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1271 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1274 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1275 self.assertEqual(rx[IP].ttl, 19)
1277 # send a packets that are routed into the tunnel
1279 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1280 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1281 / UDP(sport=555, dport=556)
1285 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1288 rx = IP(peer_1.decrypt_transport(rx, True))
1290 # chech the oringial packet is present
1291 self.assertEqual(rx[IP].dst, p[IP].dst)
1292 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
1294 # send packets into the tunnel, expect to receive them on
1298 peer_1.mk_tunnel_header(self.pg1, True)
1299 / Wireguard(message_type=4, reserved_zero=0)
1300 / WireguardTransport(
1301 receiver_index=peer_1.sender,
1303 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1305 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1306 / UDP(sport=222, dport=223)
1312 for ii in range(255)
1315 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1318 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1319 self.assertEqual(rx[IP].ttl, 19)
1321 r1.remove_vpp_config()
1322 peer_1.remove_vpp_config()
1323 wg0.remove_vpp_config()
1325 def test_wg_multi_peer(self):
1326 """multiple peer setup"""
1330 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1331 wg1 = VppWgInterface(self, self.pg2.local_ip4, port + 1).add_vpp_config()
1335 # Check peer counter
1336 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
1338 self.pg_enable_capture(self.pg_interfaces)
1341 # Create many peers on sencond interface
1343 self.pg2.generate_remote_hosts(NUM_PEERS)
1344 self.pg2.configure_ipv4_neighbors()
1345 self.pg1.generate_remote_hosts(NUM_PEERS)
1346 self.pg1.configure_ipv4_neighbors()
1352 for i in range(NUM_PEERS):
1357 self.pg1.remote_hosts[i].ip4,
1359 ["10.0.%d.4/32" % i],
1367 [VppRoutePath(self.pg1.remote_hosts[i].ip4, wg0.sw_if_index)],
1375 self.pg2.remote_hosts[i].ip4,
1377 ["10.100.%d.4/32" % i],
1385 [VppRoutePath(self.pg2.remote_hosts[i].ip4, wg1.sw_if_index)],
1389 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS * 2)
1391 self.logger.info(self.vapi.cli("show wireguard peer"))
1392 self.logger.info(self.vapi.cli("show wireguard interface"))
1393 self.logger.info(self.vapi.cli("show adj 37"))
1394 self.logger.info(self.vapi.cli("sh ip fib 172.16.3.17"))
1395 self.logger.info(self.vapi.cli("sh ip fib 10.11.3.0"))
1399 r.remove_vpp_config()
1401 r.remove_vpp_config()
1405 self.assertTrue(p.query_vpp_config())
1406 p.remove_vpp_config()
1408 self.assertTrue(p.query_vpp_config())
1409 p.remove_vpp_config()
1411 wg0.remove_vpp_config()
1412 wg1.remove_vpp_config()
1414 def test_wg_multi_interface(self):
1415 """Multi-tunnel on the same port"""
1418 # Create many wireguard interfaces
1420 self.pg1.generate_remote_hosts(NUM_IFS)
1421 self.pg1.configure_ipv4_neighbors()
1422 self.pg0.generate_remote_hosts(NUM_IFS)
1423 self.pg0.configure_ipv4_neighbors()
1425 # Create interfaces with a peer on each
1429 for i in range(NUM_IFS):
1430 # Use the same port for each interface
1431 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1439 self.pg1.remote_hosts[i].ip4,
1441 ["10.0.%d.0/24" % i],
1450 [VppRoutePath("10.0.%d.4" % i, wg0.sw_if_index)],
1454 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_IFS)
1456 for i in range(NUM_IFS):
1457 # send a valid handsake init for which we expect a response
1458 p = peers[i].mk_handshake(self.pg1)
1459 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1460 peers[i].consume_response(rx[0])
1462 # send a data packet from the peer through the tunnel
1463 # this completes the handshake
1465 IP(src="10.0.%d.4" % i, dst=self.pg0.remote_hosts[i].ip4, ttl=20)
1466 / UDP(sport=222, dport=223)
1469 d = peers[i].encrypt_transport(p)
1470 p = peers[i].mk_tunnel_header(self.pg1) / (
1471 Wireguard(message_type=4, reserved_zero=0)
1472 / WireguardTransport(
1473 receiver_index=peers[i].sender,
1475 encrypted_encapsulated_packet=d,
1478 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1480 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
1481 self.assertEqual(rx[IP].ttl, 19)
1483 # send a packets that are routed into the tunnel
1484 for i in range(NUM_IFS):
1486 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1487 / IP(src=self.pg0.remote_hosts[i].ip4, dst="10.0.%d.4" % i)
1488 / UDP(sport=555, dport=556)
1492 rxs = self.send_and_expect(self.pg0, p * 64, self.pg1)
1495 rx = IP(peers[i].decrypt_transport(rx))
1497 # check the oringial packet is present
1498 self.assertEqual(rx[IP].dst, p[IP].dst)
1499 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
1501 # send packets into the tunnel
1502 for i in range(NUM_IFS):
1505 peers[i].mk_tunnel_header(self.pg1)
1506 / Wireguard(message_type=4, reserved_zero=0)
1507 / WireguardTransport(
1508 receiver_index=peers[i].sender,
1510 encrypted_encapsulated_packet=peers[i].encrypt_transport(
1513 src="10.0.%d.4" % i,
1514 dst=self.pg0.remote_hosts[i].ip4,
1517 / UDP(sport=222, dport=223)
1526 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1529 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
1530 self.assertEqual(rx[IP].ttl, 19)
1533 r.remove_vpp_config()
1535 p.remove_vpp_config()
1537 i.remove_vpp_config()
1539 def test_wg_event(self):
1542 ESTABLISHED_FLAG = (
1543 VppEnum.vl_api_wireguard_peer_flags_t.WIREGUARD_PEER_ESTABLISHED
1545 DEAD_FLAG = VppEnum.vl_api_wireguard_peer_flags_t.WIREGUARD_PEER_STATUS_DEAD
1548 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1549 wg1 = VppWgInterface(self, self.pg2.local_ip4, port + 1).add_vpp_config()
1553 # Check peer counter
1554 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
1556 self.pg_enable_capture(self.pg_interfaces)
1561 self.pg2.generate_remote_hosts(NUM_PEERS)
1562 self.pg2.configure_ipv4_neighbors()
1563 self.pg1.generate_remote_hosts(NUM_PEERS)
1564 self.pg1.configure_ipv4_neighbors()
1570 for i in range(NUM_PEERS):
1575 self.pg1.remote_hosts[i].ip4,
1577 ["10.0.%d.4/32" % i],
1585 [VppRoutePath(self.pg1.remote_hosts[i].ip4, wg0.sw_if_index)],
1593 self.pg2.remote_hosts[i].ip4,
1595 ["10.100.%d.4/32" % i],
1603 [VppRoutePath(self.pg2.remote_hosts[i].ip4, wg1.sw_if_index)],
1607 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS * 2)
1609 # Want events from the first perr of wg0
1610 # and from all wg1 peers
1611 peers_0[0].want_events()
1614 for i in range(NUM_PEERS):
1615 # send a valid handsake init for which we expect a response
1616 p = peers_0[i].mk_handshake(self.pg1)
1617 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1618 peers_0[i].consume_response(rx[0])
1620 peers_0[0].wait_event(ESTABLISHED_FLAG)
1622 p = peers_1[i].mk_handshake(self.pg2)
1623 rx = self.send_and_expect(self.pg2, [p], self.pg2)
1624 peers_1[i].consume_response(rx[0])
1626 wg1.wait_events(ESTABLISHED_FLAG, [peers_1[0].index, peers_1[1].index])
1630 r.remove_vpp_config()
1632 r.remove_vpp_config()
1635 for i in range(NUM_PEERS):
1636 self.assertTrue(peers_0[i].query_vpp_config())
1637 peers_0[i].remove_vpp_config()
1639 peers_0[i].wait_event(0)
1640 peers_0[i].wait_event(DEAD_FLAG)
1642 self.assertTrue(p.query_vpp_config())
1643 p.remove_vpp_config()
1645 p.wait_event(DEAD_FLAG)
1647 wg0.remove_vpp_config()
1648 wg1.remove_vpp_config()
1651 class WireguardHandoffTests(TestWg):
1652 """Wireguard Tests in multi worker setup"""
1654 vpp_worker_count = 2
1656 def test_wg_peer_init(self):
1662 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1667 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.2.0/24", "10.11.3.0/24"]
1669 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1672 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1675 # send a valid handsake init for which we expect a response
1676 p = peer_1.mk_handshake(self.pg1)
1678 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1680 peer_1.consume_response(rx[0])
1682 # send a data packet from the peer through the tunnel
1683 # this completes the handshake and pins the peer to worker 0
1685 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1686 / UDP(sport=222, dport=223)
1689 d = peer_1.encrypt_transport(p)
1690 p = peer_1.mk_tunnel_header(self.pg1) / (
1691 Wireguard(message_type=4, reserved_zero=0)
1692 / WireguardTransport(
1693 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1696 rxs = self.send_and_expect(self.pg1, [p], self.pg0, worker=0)
1699 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1700 self.assertEqual(rx[IP].ttl, 19)
1702 # send a packets that are routed into the tunnel
1703 # and pins the peer tp worker 1
1705 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1706 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1707 / UDP(sport=555, dport=556)
1710 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=1)
1711 peer_1.validate_encapped(rxs, pe)
1713 # send packets into the tunnel, from the other worker
1716 peer_1.mk_tunnel_header(self.pg1)
1717 / Wireguard(message_type=4, reserved_zero=0)
1718 / WireguardTransport(
1719 receiver_index=peer_1.sender,
1721 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1723 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1724 / UDP(sport=222, dport=223)
1730 for ii in range(255)
1733 rxs = self.send_and_expect(self.pg1, p, self.pg0, worker=1)
1736 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1737 self.assertEqual(rx[IP].ttl, 19)
1739 # send a packets that are routed into the tunnel
1741 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=0)
1743 peer_1.validate_encapped(rxs, pe)
1745 r1.remove_vpp_config()
1746 peer_1.remove_vpp_config()
1747 wg0.remove_vpp_config()
1749 @unittest.skip("test disabled")
1750 def test_wg_multi_interface(self):
1751 """Multi-tunnel on the same port"""