]>
Commit | Line | Data |
---|---|---|
86439e8d DS |
1 | #!/usr/bin/env python |
2 | # | |
3 | # mcast-tx.py | |
4 | # | |
5 | # Copyright (c) 2018 Cumulus Networks, Inc. | |
6 | # | |
7 | # Permission to use, copy, modify, and/or distribute this software | |
8 | # for any purpose with or without fee is hereby granted, provided | |
9 | # that the above copyright notice and this permission notice appear | |
10 | # in all copies. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS" AND Cumulus Networks DISCLAIMS ALL WARRANTIES | |
13 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
14 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR | |
15 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY | |
16 | # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
17 | # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | |
18 | # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | |
19 | # OF THIS SOFTWARE. | |
20 | # | |
21 | ||
22 | import argparse | |
23 | import logging | |
24 | import socket | |
25 | import struct | |
26 | import time | |
f635350e | 27 | import sys |
86439e8d | 28 | |
787e7624 | 29 | logging.basicConfig( |
30 | level=logging.DEBUG, format="%(asctime)s %(levelname)5s: %(message)s" | |
31 | ) | |
86439e8d DS |
32 | |
33 | # Color the errors and warnings in red | |
787e7624 | 34 | logging.addLevelName( |
35 | logging.ERROR, "\033[91m %s\033[0m" % logging.getLevelName(logging.ERROR) | |
36 | ) | |
37 | logging.addLevelName( | |
38 | logging.WARNING, "\033[91m%s\033[0m" % logging.getLevelName(logging.WARNING) | |
39 | ) | |
86439e8d DS |
40 | log = logging.getLogger(__name__) |
41 | ||
787e7624 | 42 | parser = argparse.ArgumentParser( |
f635350e | 43 | description="Multicast packet generator" |
787e7624 | 44 | ) |
45 | parser.add_argument("group", help="Multicast IP") | |
46 | parser.add_argument("ifname", help="Interface name") | |
47 | parser.add_argument("--port", type=int, help="UDP port number", default=1000) | |
48 | parser.add_argument("--ttl", type=int, help="time-to-live", default=20) | |
49 | parser.add_argument("--count", type=int, help="Packets to send", default=1) | |
50 | parser.add_argument("--interval", type=int, help="ms between packets", default=100) | |
86439e8d DS |
51 | args = parser.parse_args() |
52 | ||
53 | # Create the datagram socket | |
54 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | |
55 | ||
56 | # IN.SO_BINDTODEVICE is not defined in some releases of python but it is 25 | |
57 | # https://github.com/sivel/bonding/issues/10 | |
58 | # | |
59 | # Bind our socket to ifname | |
f635350e MS |
60 | # |
61 | # Note ugly python version incompatibility | |
62 | # | |
63 | if sys.version_info[0] > 2: | |
64 | sock.setsockopt( | |
65 | socket.SOL_SOCKET, 25, struct.pack("%ds" % len(args.ifname), | |
66 | args.ifname.encode('utf-8')) | |
67 | ) | |
68 | else: | |
69 | sock.setsockopt( | |
70 | socket.SOL_SOCKET, 25, struct.pack("%ds" % len(args.ifname), args.ifname) | |
71 | ) | |
86439e8d DS |
72 | |
73 | # We need to make sure our sendto() finishes before we close the socket | |
74 | sock.setblocking(1) | |
75 | ||
76 | # Set the time-to-live | |
787e7624 | 77 | sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, struct.pack("b", args.ttl)) |
86439e8d DS |
78 | |
79 | ms = args.interval / 1000.0 | |
80 | ||
81 | # Send data to the multicast group | |
f635350e | 82 | for x in range(args.count): |
787e7624 | 83 | log.info( |
84 | "TX multicast UDP packet to %s:%d on %s" % (args.group, args.port, args.ifname) | |
85 | ) | |
f635350e MS |
86 | |
87 | # | |
88 | # Note ugly python version incompatibility | |
89 | # | |
90 | if sys.version_info[0] > 2: | |
91 | sent = sock.sendto(b"foobar %d" % x, (args.group, args.port)) | |
92 | else: | |
93 | sent = sock.sendto("foobar %d" % x, (args.group, args.port)) | |
86439e8d DS |
94 | |
95 | if args.count > 1 and ms: | |
96 | time.sleep(ms) | |
97 | ||
98 | sock.close() |