]> git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/lib/mcast-tester.py
doc: Add `show ipv6 rpf X:X::X:X` command to docs
[mirror_frr.git] / tests / topotests / lib / mcast-tester.py
1 #!/usr/bin/env python3
2 #
3 # Copyright (C) 2021 by
4 # Network Device Education Foundation, Inc. ("NetDEF")
5 #
6 # Permission to use, copy, modify, and/or distribute this software for any
7 # purpose with or without fee is hereby granted, provided that the above
8 # copyright notice and this permission notice appear in all copies.
9 #
10 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
11 # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 # AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
13 # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
15 # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 # PERFORMANCE OF THIS SOFTWARE.
17
18 """
19 Subscribe to a multicast group so that the kernel sends an IGMP JOIN
20 for the multicast group we subscribed to.
21 """
22
23 import argparse
24 import json
25 import os
26 import socket
27 import struct
28 import subprocess
29 import sys
30 import time
31
32
33 #
34 # Functions
35 #
36 def interface_name_to_index(name):
37 "Gets the interface index using its name. Returns None on failure."
38 interfaces = json.loads(subprocess.check_output("ip -j link show", shell=True))
39
40 for interface in interfaces:
41 if interface["ifname"] == name:
42 return interface["ifindex"]
43
44 return None
45
46
47 def multicast_join(sock, ifindex, group, port):
48 "Joins a multicast group."
49 mreq = struct.pack(
50 "=4sLL", socket.inet_aton(args.group), socket.INADDR_ANY, ifindex
51 )
52
53 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
54 sock.bind((group, port))
55 sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
56
57
58 #
59 # Main code.
60 #
61 parser = argparse.ArgumentParser(description="Multicast RX utility")
62 parser.add_argument("group", help="Multicast IP")
63 parser.add_argument("interface", help="Interface name")
64 parser.add_argument("--socket", help="Point to topotest UNIX socket")
65 parser.add_argument(
66 "--send", help="Transmit instead of join with interval", type=float, default=0
67 )
68 args = parser.parse_args()
69
70 ttl = 16
71 port = 1000
72
73 # Get interface index/validate.
74 ifindex = interface_name_to_index(args.interface)
75 if ifindex is None:
76 sys.stderr.write("Interface {} does not exists\n".format(args.interface))
77 sys.exit(1)
78
79 # We need root privileges to set up multicast.
80 if os.geteuid() != 0:
81 sys.stderr.write("ERROR: You must have root privileges\n")
82 sys.exit(1)
83
84 # Wait for topotest to synchronize with us.
85 if not args.socket:
86 toposock = None
87 else:
88 toposock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0)
89 while True:
90 try:
91 toposock.connect(args.socket)
92 break
93 except ConnectionRefusedError:
94 time.sleep(1)
95 continue
96 # Set topotest socket non blocking so we can multiplex the main loop.
97 toposock.setblocking(False)
98
99 msock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
100 if args.send > 0:
101 # Prepare multicast bit in that interface.
102 msock.setsockopt(
103 socket.SOL_SOCKET,
104 25,
105 struct.pack("%ds" % len(args.interface), args.interface.encode("utf-8")),
106 )
107 # Set packets TTL.
108 msock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, struct.pack("b", ttl))
109 # Block to ensure packet send.
110 msock.setblocking(True)
111 else:
112 multicast_join(msock, ifindex, args.group, port)
113
114
115 def should_exit():
116 if not toposock:
117 # If we are sending then we have slept
118 if not args.send:
119 time.sleep(100)
120 return False
121 else:
122 try:
123 data = toposock.recv(1)
124 if data == b"":
125 print(" -> Connection closed")
126 return True
127 except BlockingIOError:
128 return False
129
130
131 counter = 0
132 while not should_exit():
133 if args.send > 0:
134 msock.sendto(b"test %d" % counter, (args.group, port))
135 counter += 1
136 time.sleep(args.send)
137
138 msock.close()
139 sys.exit(0)