blob: b69770b6b26082c85d8cc6f343a9701cc03af8de [file] [log] [blame]
Nathan Knuthab966e52017-01-30 07:48:13 -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 """
14
15TIBIT_VERSION_NUMBER = '1.1.2'
16
17import time
18import logging
19import argparse
20import sys
21import inspect
22
23logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
24from scapy.all import Dot1Q
25from scapy.all import sniff
26from scapy.all import IP, UDP
27from scapy.packet import Packet, bind_layers
28from scapy.fields import StrField
29from scapy.layers.l2 import Ether
30from scapy.main import interact
31from scapy.sendrecv import sendp
32from scapy.sendrecv import srp1
33from scapy.config import conf
34conf.verb = None
35
36import fcntl, socket, struct # for get hw address
37
38# TODO should remove import *
39from EOAM_TLV import *
40
41EOAM_MULTICAST_ADDRESS = '01:80:c2:00:00:02'
42IGMP_MULTICAST_ADDRESS = '01:00:5e:00:00:01' # for test
43
44class EOAM():
45 """ EOAM frame layer """
46 def __init__(self, ctag=None, dryrun=False, stag=None,
47 verbose=False, etype='8809',
48 dst=EOAM_MULTICAST_ADDRESS,
49 hexdump=False, interface='eth0',
50 sleep=1.0):
51 self.verbose = verbose
52 self.dst = dst
53 self.dryrun = dryrun
54 self.hexdump = hexdump
55 self.interface = interface
56 self.etype = int(etype, 16)
57 self.stag = stag
58 self.ctag = ctag
59 self.sleep = sleep
60 if (self.verbose == True):
61 print("=== Settings ================")
62 print("ctag = %s" % self.ctag)
63 print("stag = %s" % self.stag)
64 print("dst = %s" % self.dst)
65 print("dryrun = %s" % self.dryrun)
66 print("hexdump = %s" % self.hexdump)
67 print("interface = %s" % self.interface)
68 print("etype = 0x%04x" % self.etype)
69 print("verbose = %s" % self.verbose)
70 print("=== END Settings ============")
71
72 def send_frame(self, frame_body):
73 PACKET = Ether()
74 PACKET.length = 64
75 PACKET.dst = self.dst
76 PACKET.src = self.getHwAddr(self.interface)
77 if self.stag:
78 # WARNING: September/2016: This should be 0x88a8, but the Intel 10G
79 # hardware I am currently using does not support receiving a TPID of
80 # 0x88a8. So, I send double CTAGs, and I usually set this to 0x8100.
81 # (NOTE: The Intel hardware can send a TPID of 0x88a8)
82 PACKET.type = 0x8100
83 if self.ctag:
84 PACKET/=Dot1Q(type=0x8100,vlan=int(self.stag))
85 PACKET/=Dot1Q(type=self.etype,vlan=int(self.ctag))
86 else:
87 PACKET/=Dot1Q(type=self.etype,vlan=int(self.stag))
88 else:
89 if self.ctag:
90 PACKET.type = 0x8100
91 PACKET/=Dot1Q(type=self.etype,vlan=int(self.ctag))
92 else:
93 PACKET.type = self.etype
94# PACKET/=Dot1Q(type=self.etype, vlan=int(self.ctag))
95 PACKET/=SlowProtocolsSubtype()/FlagsBytes()/OAMPDU()
96 PACKET/=frame_body
97 PACKET/=EndOfPDU()
98 if (self.verbose == True):
99 PACKET.show()
100 print '###[ Frame Length %d (before padding) ]###' % len(PACKET)
101 if (self.hexdump == True):
102 print hexdump(PACKET)
103 if (self.dryrun != True):
104 sendp(PACKET, iface=self.interface, verbose=self.verbose)
105 time.sleep(self.sleep)
106 return PACKET
107
108 def get_request(self, TLV):
109 return self.send_frame(CablelabsOUI()/DPoEOpcode_GetRequest()/TLV)
110
111 def set_request(self, TLV):
112 return self.send_frame(CablelabsOUI()/DPoEOpcode_SetRequest()/TLV)
113
114 def send_multicast_register(self, TLV):
115 '''
116 Note, for mulicast, the standard specifies a register message
117 with ActionFlags of either Register or Deregister
118 '''
119 return self.send_frame(CablelabsOUI()/DPoEOpcode_MulticastRegister()/TLV)
120
121 def set_request_broadcom(self, TLV):
122 return self.send_frame(BroadcomOUI()/DPoEOpcode_SetRequest()/TLV)
123
124 def getHwAddr(self, ifname):
125 if (not self.dryrun):
126 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
127 info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', ifname[:15]))
128 else:
129 info = range(1, 24)
130 info[18:24] = ['0','1','2','3','4','5']
131
132 return ':'.join(['%02x' % ord(char) for char in info[18:24]])
133
134
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: 0.5 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')
166
167 args = parser.parse_args()
168
169 if (args.dryrun == True):
170 args.sleep = 0.0
171
172 eoam = EOAM(
173 dryrun=args.dryrun,
174 dst=args.dst,
175 etype=args.etype,
176 hexdump=args.hexdump,
177 interface=args.interface,
178 stag=args.stag,
179 ctag=args.ctag,
180 verbose=args.verbose,
181 )
182
183 if (not args.critical
184 and not args.test
185 and not args.test_add
186 and not args.test_del
187 and not args.test_clr):
188 print 'WARNING: *** No frames sent, please specify \'test\' or \'critical\', etc. See --help'
189
190 # Critical OAM Messages
191 if (args.critical == True):
192
193 # OAM GET Requests
194 print 'GET DeviceId and MAX Logical Links Message'
195 eoam.get_request(DeviceId()/MaxLogicalLinks())
196
197 print 'SET Report Thresholds Message'
198 eoam.set_request(ReportThresholdsSet())
199
200 print 'SET OAM Frame Rate Message'
201 eoam.set_request(OamFrameRateSet())
202
203 print 'GET multiple - Device and Manufacturing Info'
204 eoam.get_request(DONUObject()/DeviceId()/MaxLogicalLinks()/
205 FirmwareInfo()/ChipsetInfo()/NumberOfNetworkPorts()/NumberOfS1Interfaces())
206
207 print 'GET - LLID Queue Configuration'
208 eoam.get_request(DONUObject()/LLIDQueueConfiguration())
209
210 print 'GET - ONU Manufacturer Organization Name'
211 eoam.get_request(DONUObject()/OnuManufacturerOrganizationName())
212
213 print 'GET - ONU Firmware Mfg Time Varying Controls'
214 eoam.get_request(DONUObject()/FirmwareMfgTimeVaryingControls())
215
216 print 'GET - ONU Vendor Name'
217 eoam.get_request(DONUObject()/VendorName())
218
219 print 'GET - ONU Model Number'
220 eoam.get_request(DONUObject()/ModelNumber())
221
222 print 'GET - ONU Hardware Version'
223 eoam.get_request(DONUObject()/HardwareVersion())
224
225 print 'SET - Clear Port Ingress Rules -- Network Port Object'
226 eoam.set_request(NetworkPortObject()/ClearPortIngressRules())
227
228 print 'SET - Clear Port Ingress Rules -- User Port Object'
229 eoam.set_request(UserPortObject()/ClearPortIngressRules())
230
231 print 'SET - Broadcom Specific TLVs'
232 eoam.set_request_broadcom(Broadcom07_7F_F1_Set01()/Broadcom07_7F_F1_Set02()/
233 Broadcom07_7F_F1_Set03()/Broadcom07_7F_F1_Set04())
234
235 print 'SET - Multicast Register Message 01'
236 eoam.send_multicast_register(MulticastRegisterSetSumitomo01())
237
238 print 'SET - Multicast Register Message 02'
239 eoam.send_multicast_register(MulticastRegisterSetSumitomo02())
240
241 print 'SET - Custom Field EtherType'
242 eoam.set_request(UserPortObject()/CustomFieldEtherType())
243
244 print 'SET - Custom Field Generic L3'
245 eoam.set_request(UserPortObject()/CustomFieldGenericL3())
246
247 print 'SET - MAC Learning MIN/MAX/Age Limit -- User Port Object'
248 eoam.set_request(UserPortObject()/MacLearningMaxAllowedSet()/DynamicAddressAgeLimitSet()/
249 SourceAddressAdmissionControlSet()/MacLearningMinGuaranteeSet())
250
251 print 'SET - MAC Learning/Flooding/Local Switching -- D-ONU Port Object'
252 eoam.set_request(DONUObject()/MacLearningAggregateLimitSet()/FloodUnknownSet()/LocalSwitchingSet())
253
254 print 'SET - Report Thresholds -- Unicast Logical Link'
255 eoam.set_request(UnicastLogicalLink()/UnicastLogicalLinkReportThresholdsSet())
256
257 print 'SET - Port Ingress Rule -- Network Port Object -- Precedence 12'
258 eoam.set_request(NetworkPortObject()/
259 PortIngressRuleHeader(precedence=12)/
260 PortIngressRuleClauseMatchLength01(operator=1)/
261 PortIngressRuleResultForward()/
262 PortIngressRuleResultQueue(objecttype=0x0003)/
263 PortIngressRuleTerminator()/
264 AddPortIngressRule())
265
266 print 'SET - Port Ingress Rule -- User Port Object -- Precedence 13'
267 eoam.set_request(UserPortObject()/
268 PortIngressRuleHeader(precedence=13)/
269 PortIngressRuleClauseMatchLength00(fieldcode=1, operator=7)/
270 PortIngressRuleResultQueue(objecttype=0x0002)/
271 PortIngressRuleTerminator()/
272 AddPortIngressRule())
273
274 print 'SET - Port Ingress Rule -- User Port Object -- Precedence 7 Discard 01'
275 eoam.set_request(UserPortObject()/
276 PortIngressRuleHeader(precedence=7)/
277 PortIngressRuleClauseMatchLength06(fieldcode=1, operator=1)/
278 PortIngressRuleResultDiscard()/
279 PortIngressRuleTerminator()/
280 AddPortIngressRule())
281
282
283 print 'SET - Port Ingress Rule -- User Port Object -- Precedence 7 Discard 02'
284 eoam.set_request(UserPortObject()/
285 PortIngressRuleHeader(precedence=7)/
286 PortIngressRuleClauseMatchLength06(fieldcode=1, operator=1, match5=0x02)/
287 PortIngressRuleClauseMatchLength02(fieldcode=0x19, operator=1, match=0x8889)/
288 PortIngressRuleClauseMatchLength01(fieldcode=0x1a, operator=1, match=0x03)/
289 PortIngressRuleResultDiscard()/
290 PortIngressRuleTerminator()/
291 AddPortIngressRule())
292
293 print 'GET - D-ONU Object -- Firmware Filename'
294 eoam.set_request(DONUObject()/FirmwareFilename())
295
296 print 'SET - User Port Object 0 -- Broadcom Specific TLVs'
297 eoam.set_request_broadcom(UserPortObject(number=0)/Broadcom07_7F_F6_Set())
298
299 print 'SET - User Port Object 1 -- Broadcom Specific TLVs'
300 eoam.set_request_broadcom(UserPortObject(number=1)/Broadcom07_7F_F6_Set())
301
302 print 'SET - User Port Object 0 -- Clause 30 Attributes -- MAC Enable'
303 eoam.set_request(UserPortObject()/Clause30AttributesMacEnable())
304
305 print 'SET - IPMC Forwarding Rule Configuration'
306 eoam.set_request(IpmcForwardingRuleConfiguration())
307
308 print 'SET - Enable User Traffic -- Unicast Logical Link'
309 eoam.set_request(UnicastLogicalLink()/EnableUserTraffic())
310
311 if (args.test == True):
312 print 'SET - Multicast Register Message 01'
313 eoam.send_multicast_register(MulticastRegisterSet(MulticastLink=0x3ff0, UnicastLink=0x120f))
314
315 #print 'SET - Multicast Deregister Message 02'
316 eoam.send_multicast_register(MulticastRegisterSet(ActionFlags="Deregister",MulticastLink=0x3ff0, UnicastLink=0x120f))
317
318 if (args.test_clr == True):
319 print 'SET Clear Static MAC Table -- User Port Object'
320 eoam.set_request(ClearStaticMacTable())
321
322 elif (args.test_add == True):
323 print 'SET Add Static MAC Address -- User Port Object'
324 eoam.set_request(AddStaticMacAddress(mac=IGMP_MULTICAST_ADDRESS))
325
326 elif (args.test_del == True):
327 print 'SET Delete Static MAC Address -- User Port Object'
328 eoam.set_request(DeleteStaticMacAddress(mac=IGMP_MULTICAST_ADDRESS))
329
330
331
332 # EXTERNAL OAM LIB TESTING
333 #import tboam
334 #tboam.get_request(f.branch, f.leaf)
335 #print 'SET - User Port Object 1 -- Broadcom Specific TLVs'
336 #f = eoam.set_request_broadcom(UserPortObject(number=1)/Broadcom07_7F_F6_Set())
337 #print("=== receive frame ===========")
338 #Now, pretend I just received this frame.
339 #f.show()
340 #tboam.set_request(f.branch, f.leaf)
341
342 # Examples
343 #oam_frame = eoam.get_request(UserPortObject()/LoopbackEnable())
344 #oam_frame = eoam.get_reqeust(UserPortObject()/LoopbackDisable())
345 #oam_frame = eoam.set_request(UserPortObject()/LoopbackEnable())
346 #oam_frame = eoam.set_request(UnicastLogicalLink()/AlarmReportingSet())
347 #oam_frame = eoam.get_request(UserPortObject()/BytesDropped())
348 #oam_frame = eoam.get_request(UserPortObject()/TxBytesUnused())
349 #print 'GET -- User Port Object -- Rx Frame 512-1023'
350 #oam_frame = eoam.get_request(UserPortObject()/RxFrame_512_1023())
351 #print 'GET -- User Port Object -- Tx Frame 512-1023'
352 #oam_frame = eoam.get_request(UserPortObject()/TxFrame_512_1023())
353 #oam_frame = eoam.get_request(NetworkPortObject()/BytesDropped())
354 #oam_frame = eoam.get_request(NetworkPortObject()/TxBytesUnused())
355 #print 'GET -- Network Port Object -- Rx Frame 512-1023'
356 #oam_frame = eoam.get_request(NetworkPortObject()/RxFrame_512_1023())
357 #print 'GET -- Network Port Object -- Tx Frame 512-1023'
358 #oam_frame = eoam.get_request(NetworkPortObject()/TxFrame_512_1023())