blob: 69c056ee4ddc296f8c91c308c7aab282cc918215 [file] [log] [blame]
Zsolt Haraszti348d1932016-12-10 01:10:07 -08001#!/usr/bin/env python
2#--------------------------------------------------------------------------#
3# Copyright (C) 2015 - 2016 by Tibit Communications, Inc. #
4# All rights reserved. #
5# #
6# _______ ____ _ ______ #
7# /_ __(_) __ )(_)_ __/ #
8# / / / / __ / / / / #
9# / / / / /_/ / / / / #
10# /_/ /_/_____/_/ /_/ #
11# #
12#--------------------------------------------------------------------------#
13""" EOAM protocol implementation in scapy """
Zsolt Haraszti348d1932016-12-10 01:10:07 -080014
Nathan Knuth6e57f332016-12-22 15:49:20 -080015TIBIT_VERSION_NUMBER = '1.1.4'
Zsolt Haraszti348d1932016-12-10 01:10:07 -080016
17import argparse
18import logging
Nathan Knuth6e57f332016-12-22 15:49:20 -080019import time
20from hexdump import hexdump
Zsolt Haraszti348d1932016-12-10 01:10:07 -080021
22logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
23from scapy.layers.l2 import Ether, Dot1Q
24from scapy.sendrecv import sendp
Nathan Knuth6e57f332016-12-22 15:49:20 -080025from scapy.fields import PacketField
26from scapy.packet import bind_layers
Zsolt Haraszti348d1932016-12-10 01:10:07 -080027
Nathan Knuth6e57f332016-12-22 15:49:20 -080028import fcntl, socket, struct # for get hw address
Zsolt Haraszti348d1932016-12-10 01:10:07 -080029
30# TODO should remove import *
31from EOAM_TLV import *
32
33EOAM_MULTICAST_ADDRESS = '01:80:c2:00:00:02'
34IGMP_MULTICAST_ADDRESS = '01:00:5e:00:00:01' # for test
35
36class EOAM():
37 """ EOAM frame layer """
38 def __init__(self, ctag=None, dryrun=False, stag=None,
39 verbose=False, etype='8809',
40 dst=EOAM_MULTICAST_ADDRESS,
41 hexdump=False, interface='eth0',
42 sleep=2.0):
43 self.verbose = verbose
44 self.dst = dst
45 self.dryrun = dryrun
46 self.hexdump = hexdump
47 self.interface = interface
48 self.etype = int(etype, 16)
49 self.stag = stag
50 self.ctag = ctag
51 self.sleep = sleep
52 if (self.verbose == True):
53 print("=== Settings ================")
54 print("ctag = %s" % self.ctag)
55 print("stag = %s" % self.stag)
56 print("dst = %s" % self.dst)
57 print("dryrun = %s" % self.dryrun)
58 print("hexdump = %s" % self.hexdump)
59 print("interface = %s" % self.interface)
60 print("etype = 0x%04x" % self.etype)
61 print("verbose = %s" % self.verbose)
62 print("sleep = %d" % self.sleep)
63 print("=== END Settings ============")
64
65 def send_frame(self, frame_body):
66 PACKET = Ether()
67 PACKET.dst = self.dst
68 PACKET.src = self.getHwAddr(self.interface)
69 if self.stag:
70 # WARNING: September/2016: This should be 0x88a8, but the Intel 10G
71 # hardware I am currently using does not support receiving a TPID of
72 # 0x88a8. So, I send double CTAGs, and I usually set this to 0x8100.
73 # (NOTE: The Intel hardware can send a TPID of 0x88a8)
74 PACKET.type = 0x8100
75 if self.ctag:
76 PACKET/=Dot1Q(type=0x8100,vlan=int(self.stag))
77 PACKET/=Dot1Q(type=self.etype,vlan=int(self.ctag))
78 else:
79 PACKET/=Dot1Q(type=self.etype,vlan=int(self.stag))
80 else:
81 if self.ctag:
82 PACKET.type = 0x8100
83 PACKET/=Dot1Q(type=self.etype,vlan=int(self.ctag))
84 else:
85 PACKET.type = self.etype
86# PACKET/=Dot1Q(type=self.etype, vlan=int(self.ctag))
87 PACKET/=SlowProtocolsSubtype()/FlagsBytes()/OAMPDU()
88 PACKET/=frame_body
89 PACKET/=EndOfPDU()
90 if (self.verbose == True):
91 PACKET.show()
92 print '###[ Frame Length %d (before padding) ]###' % len(PACKET)
93 if (self.hexdump == True):
Nathan Knuth6e57f332016-12-22 15:49:20 -080094 print hexdump(str(PACKET))
Zsolt Haraszti348d1932016-12-10 01:10:07 -080095 if (self.dryrun != True):
96 sendp(PACKET, iface=self.interface)
97 time.sleep(self.sleep)
98 return PACKET
99
100 def get_request(self, TLV):
101 return self.send_frame(CablelabsOUI()/DPoEOpcode_GetRequest()/TLV)
102
103 def set_request(self, TLV):
104 return self.send_frame(CablelabsOUI()/DPoEOpcode_SetRequest()/TLV)
105
106 def send_multicast_register(self, TLV):
107 '''
108 Note, for mulicast, the standard specifies a register message
109 with ActionFlags of either Register or Deregister
110 '''
111 return self.send_frame(CablelabsOUI()/DPoEOpcode_MulticastRegister()/TLV)
112
113 def set_request_broadcom(self, TLV):
114 return self.send_frame(BroadcomOUI()/DPoEOpcode_SetRequest()/TLV)
115
116 def getHwAddr(self, ifname):
117 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
118 info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', ifname[:15]))
119 return ':'.join(['%02x' % ord(char) for char in info[18:24]])
120
121
Nathan Knuth6e57f332016-12-22 15:49:20 -0800122class EOAMPayload(Packet):
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800123 name = 'EOAM Payload'
124 fields_desc = [
125 ByteEnumField("subtype", 0x03, SlowProtocolsSubtypeEnum),
126 XShortField("flags", 0x0050),
127 XByteField("opcode", 0xfe),
128 PacketField("body", None, Packet),
129 BitEnumField("type", 0x00, 7, TLV_dictionary),
130 BitField("length", 0x00, 9)
131 ]
132
Nathan Knuth6e57f332016-12-22 15:49:20 -0800133bind_layers(Ether, EOAMPayload, type=0x9001)
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800134
135if __name__ == "__main__":
136 parser = argparse.ArgumentParser()
137 parser.add_argument('-d', '--dst', dest='dst', action='store', default=EOAM_MULTICAST_ADDRESS,
138 help='MAC destination (default: %s)' % EOAM_MULTICAST_ADDRESS)
139 parser.add_argument('-e', '--etype', dest='etype', action='store', default='8809',
140 help='EtherType value (default: 0x8809)')
141 parser.add_argument('-i', '--interface', dest='interface', action='store', default='eth0',
142 help='ETH interface to send (default: eth0)')
143 parser.add_argument('-s', '--stag', dest='stag', action='store', default=None,
144 help='STAG value (default: None)')
145 parser.add_argument('-c', '--ctag', dest='ctag', action='store', default=None,
146 help='CTAG value (default: None)')
147 parser.add_argument('-p', '--sleep', dest='sleep', action='store', default='1.0', type=float,
148 help='SLEEP time after frame (default: 1.0 secs)')
149 parser.add_argument('-v', '--verbose', dest='verbose', action='store_true', default=False,
150 help='verbose frame print out')
151 parser.add_argument('-x', '--hexdump', dest='hexdump', action='store_true', default=False,
152 help='Hexdump the frame')
153 parser.add_argument('-y', '--dryrun', dest='dryrun', action='store_true', default=False,
154 help='Dry run test, dont send - just print')
155
156 parser.add_argument('-t', '--test', dest='test', action='store_true', default=False,
157 help='Run commands under test')
158 parser.add_argument('-r', '--critical', dest='critical', action='store_true', default=False,
159 help='Send the critical OAM set of set_request()')
160 parser.add_argument('-ta', '--test_add', dest='test_add', action='store_true', default=False,
161 help='Run commands under test')
162 parser.add_argument('-td', '--test_del', dest='test_del', action='store_true', default=False,
163 help='Run commands under test')
164 parser.add_argument('-tc', '--test_clr', dest='test_clr', action='store_true', default=False,
165 help='Run commands under test')
Nathan Knuth6e57f332016-12-22 15:49:20 -0800166 parser.add_argument('-te', '--test_eapol', dest='test_eapol', action='store_true', default=False,
167 help='Run commands under test')
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800168
169 args = parser.parse_args()
170
171 if (args.dryrun == True):
172 args.sleep = 0.0
173
174 eoam = EOAM(
175 dryrun=args.dryrun,
176 dst=args.dst,
177 etype=args.etype,
178 hexdump=args.hexdump,
179 interface=args.interface,
180 stag=args.stag,
181 ctag=args.ctag,
182 verbose=args.verbose,
183 sleep=args.sleep
184 )
185
186 if (not args.critical
187 and not args.test
188 and not args.test_add
189 and not args.test_del
Nathan Knuth6e57f332016-12-22 15:49:20 -0800190 and not args.test_clr
191 and not args.test_eapol):
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800192 print 'WARNING: *** No frames sent, please specify \'test\' or \'critical\', etc. See --help'
193
194
195 if (args.test == True):
196 print 'SET - Multicast Register Message 01'
197 eoam.send_multicast_register(MulticastRegisterSet(MulticastLink=0x3fe0, UnicastLink=0x1008))
198
199 print 'SET - Multicast Deregister Message 02'
200 eoam.send_multicast_register(MulticastRegisterSet(ActionFlags="Deregister",MulticastLink=0x3fe0, UnicastLink=0x1008))
201
202 if (args.test_clr == True):
203 print 'SET Clear Static MAC Table -- User Port Object'
204 eoam.set_request(ClearStaticMacTable())
205
206 elif (args.test_add == True):
207 print 'SET Add Static MAC Address -- User Port Object'
208 eoam.set_request(AddStaticMacAddress(mac=IGMP_MULTICAST_ADDRESS))
209
210 elif (args.test_del == True):
211 print 'SET Delete Static MAC Address -- User Port Object'
212 eoam.set_request(DeleteStaticMacAddress(mac=IGMP_MULTICAST_ADDRESS))
Nathan Knuth6e57f332016-12-22 15:49:20 -0800213
214 if (args.test_eapol == True):
215 print 'SET - Port Ingress Rule -- User Port Object -- Precedence 32 Match 0x888e'
216 eoam.set_request(DOLTObject()/
217 PortIngressRuleHeader(precedence=32)/
218 PortIngressRuleClauseMatchLength02(fieldcode=3, operator=1, match0=0x88, match1=0x8e)/
219 PortIngressRuleResultForward()/
220 PortIngressRuleResultSet(fieldcode=7, value=0x4090)/
221 PortIngressRuleResultInsert(fieldcode=7)/
222 PortIngressRuleTerminator()/
223 AddPortIngressRule())
224
225 eoam.set_request(DOLTObject()/
226 PortIngressRuleHeader(precedence=32)/
227 PortIngressRuleClauseMatchLength02(fieldcode=3, operator=1, match0=0x88, match1=0x8e)/
228 PortIngressRuleResultForward()/
229 PortIngressRuleResultSet(fieldcode=7, value=0x4090)/
230 PortIngressRuleResultInsert(fieldcode=7)/
231 PortIngressRuleTerminator()/
232 DeletePortIngressRule())