• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1% PFCP tests
2
3# Type the following command to launch start the tests:
4# $ test/run_tests -P "load_contrib('pfcp')" -t test/contrib/pfcp.uts
5
6+ Build packets & dissect
7
8= Verify IEs
9
10import scapy.contrib.pfcp as pfcp_mod
11
12skip_IEs = [
13    IE_Base,
14    IE_Compound
15]
16
17for name, cls in pfcp_mod.__dict__.items():
18    if name.startswith("IE_") and type(cls) == Packet_metaclass and cls not in skip_IEs:
19        print("testing %s" % name)
20        pkt = cls()
21        bs = bytes(pkt)
22        restored = cls(bs)
23        assert bytes(restored) == bs
24        # TODO: also test packet field equality
25
26= Verify PCAPs
27
28~ pcaps
29
30# the following can be useful while adding more IE types
31# (e.g. updating for a newer version of the spec)
32
33def command(pkt):
34    f = []
35    for fn, fv in sorted(pkt.fields.items(), key=lambda item: item[0]):
36        if fn in ("length", "message_type"):
37            continue
38        if fn == "ietype" and not isinstance(pkt, IE_EnterpriseSpecific) and \
39           not isinstance(pkt, IE_NotImplemented):
40            continue
41        if fn.startswith("num_") or fn.endswith("_length"):
42            continue
43        if fv is None:
44            continue
45        fld = pkt.get_field(fn)
46        if isinstance(fld, ConditionalField) and not fld._evalcond(pkt):
47            continue
48        # if fv == fld.default:
49        #     continue
50        if isinstance(fv, (list, dict, set)) and len(fv) == 0:
51            continue
52        if isinstance(fv, Packet):
53            fv = command(fv)
54        elif fld.islist and fld.holds_packets and isinstance(fv, list):
55            fv = "[%s]" % ",".join(map(command, fv))
56        elif isinstance(fld, FlagsField):
57            fv = int(fv)
58        else:
59            fv = repr(fv)
60        f.append("%s=%s" % (fn, fv))
61    c = "%s(%s)" % (pkt.__class__.__name__, ", ".join(f))
62    if not isinstance(pkt.payload, NoPayload):
63        pc = command(pkt.payload)
64        if pc:
65            c += "/" + pc
66    return c
67
68broken_ies = set([])
69
70broken_ie_types = set([
71    cls.ie_type for cls in broken_ies
72])
73
74ignore = set([])
75
76def find_raw_or_not_implemented(pkt, prefix=""):
77    if prefix in ignore:
78        return False, False
79    if hasattr(pkt, "IE_list"):
80        prev = None
81        found_any = False
82        for n, ie in enumerate(pkt.IE_list, 1):
83            if type(ie) in broken_ies:
84                return False, False
85            name = "%s-%d-%s" % (prefix, n, type(ie).__name__)
86            found, leaf = find_raw_or_not_implemented(ie, prefix=name)
87            if found:
88                found_any = True
89            if found and leaf:
90                print("gotcha: %s %r" % (prefix, ie))
91                bs = b""
92                if prev is not None:
93                    bs = bytes(prev)
94                bs += bytes(ie)
95                if prev is not None:
96                    prev.show2()
97                ie.show2()
98                print("%s -- bad val: %s" % (prefix, bytes_hex(bs).decode()))
99                if len(bs) > 4:
100                    l = bs[2] * 256 + bs[3]
101                    if len(bs) >= l + 4:
102                        print("bad val (length-limited): %s" % bytes_hex(bs[:l + 4]).decode())
103                print("bad val (short): %s" % bytes_hex(bytes(ie)).decode())
104            prev = ie
105        return found_any, False
106    if isinstance(pkt, Raw):
107        bs = bytes(pkt)
108        if len(bs) > 4:
109            ie_type = bs[0] * 256 + bs[1]
110            if ie_type in broken_ie_types:
111                return False, True
112        return True, True
113    if isinstance(pkt, Padding) or isinstance(pkt, IE_NotImplemented):
114        return True, True
115    return False, True
116
117def find_mismatching_command(pkt, prefix=""):
118    c = command(pkt)
119    if hasattr(pkt, "IE_list"):
120        for n, ie in enumerate(pkt.IE_list, 1):
121            name = "%s-%d-%s" % (prefix, n, type(ie).__name__)
122            find_mismatching_command(ie, prefix=name)
123    if bytes(eval(c)) != bytes(pkt):
124        print(prefix)
125        print("ORIG: %s" % bytes_hex(bytes(pkt)))
126        print("EVAL: %s" % bytes_hex(bytes(eval(c))))
127        raise AssertionError("bad command: %s" % c)
128
129for n, pkt in enumerate(rdpcap("test/pcaps/pfcp.pcap"), 1):
130    if PFCP in pkt:
131        # if IE_DLBufferingSuggestedPacketCount in pkt:
132        #     continue
133        pkt0 = pkt[PFCP]
134        if IE_NotImplemented in pkt0 or Raw in pkt0 or IE_NotImplemented in pkt0 or Padding in pkt0:
135            found, leaf = find_raw_or_not_implemented(pkt, prefix=str(n))
136            if not found:
137                # ignored
138                continue
139            pkt0.show2()
140            raise AssertionError("IE_NotImplemented / Raw / Padding detected")
141        bs = bytes(pkt0)
142        pkt1 = PFCP(bs)
143        # TODO: diff show2() result
144        c0 = command(pkt0)
145        c1 = command(pkt1)
146        pkt2 = eval(c1)
147        c2 = command(pkt2)
148        if bytes(pkt2) != bs:
149            find_mismatching_command(pkt0, prefix=str(n))
150            print(bytes_hex(bytes(pkt2)))
151            print(bytes_hex(bs))
152            raise AssertionError("bytes(pkt2) != bs")
153        if bs != pkt0.original:
154            print(bytes_hex(bs))
155            print(bytes_hex(pkt0.original))
156            raise AssertionError("bs != pkt0.original")
157        if bytes(pkt1) != bs:
158            print(bytes_hex(bytes(pkt1)))
159            print(bytes_hex(bs))
160            raise AssertionError("bytes(pkt1) != bs")
161        if c0 != c1:
162            print("COMMAND MISMATCH:\n----\n%s\n----\n%s\n\n" % (c0, c1))
163            pkt0.show2()
164            pkt1.show2()
165            print(bytes_hex(bytes(pkt0)))
166            print("packet index: %d\n" % n)
167            raise AssertionError("c0 != c1")
168        if c0 != c2:
169            print("EVAL COMMAND MISMATCH:\n----\n%s\n----\n%s\n\n" % (c0, c2))
170            pkt0.show2()
171            pkt2.show2()
172            print(bytes_hex(bytes(pkt0)))
173            print("packet index: %d\n" % n)
174            raise AssertionError("c0 != c2")
175
176= Build and dissect PFCP Association Setup Request
177
178pfcpASReqBytes = hex_bytes("200500160000010000600004e1a47d08003c0006020465726777")
179
180pfcpASReq = PFCP(version=1, S=0, seq=1) / \
181  PFCPAssociationSetupRequest(IE_list=[
182      IE_RecoveryTimeStamp(timestamp=3785653512),
183      IE_NodeId(id_type="FQDN", id="ergw")
184  ])
185
186# print("%r" % bytes(pfcpASReq))
187# print("%r" % pfcpASReqBytes)
188assert bytes(pfcpASReq) == pfcpASReqBytes
189
190pfcpASReq = PFCP(pfcpASReqBytes)
191assert pfcpASReq.version == 1
192assert pfcpASReq.MP == 0
193assert pfcpASReq.S == 0
194assert pfcpASReq.message_type == 5
195assert pfcpASReq.length == 22
196ies = pfcpASReq[PFCPAssociationSetupRequest].IE_list
197assert isinstance(ies[0], IE_RecoveryTimeStamp)
198assert ies[0].ietype == 96
199assert ies[0].length == 4
200assert ies[0].timestamp == 3785653512
201assert isinstance(ies[1], IE_NodeId)
202assert ies[1].ietype == 60
203assert ies[1].length == 6
204assert ies[1].id_type == 2
205assert ies[1].id == b"ergw"
206
207= Build and dissect PFCP Association Setup Response
208
209pfcpASRespBytes = hex_bytes("2006008c00000100001300010100600004e1a47af9002b00020001007400092980ac1201020263708002006448f9767070207631392e30382e312d3339377e673465333431343066612d6469727479206275696c7420627920726f6f74206f6e206275696c646b697473616e64626f7820617420576564204465632031312031353a30323a3535205554432032303139")
210
211pfcpASResp = PFCP(version=1, S=0, seq=1) / \
212  PFCPAssociationSetupResponse(IE_list=[
213      IE_Cause(cause="Request accepted"),
214      IE_RecoveryTimeStamp(timestamp=3785652985),
215      IE_UPFunctionFeatures(
216          TREU=0, HEEU=0, PFDM=0, FTUP=0, TRST=0, DLBD=0, DDND=0, BUCP=0,
217          spare=0, PFDE=0, FRRT=0, TRACE=0, QUOAC=0, UDBC=0, PDIU=0, EMPU=1),
218      IE_UserPlaneIPResourceInformation(
219          ASSOSI=0, ASSONI=1, TEIDRI=2, V6=0, V4=1, teid_range=0x80,
220          ipv4="172.18.1.2", network_instance="cp"),
221      IE_EnterpriseSpecific(
222          ietype=32770,
223          enterprise_id=18681,
224          data="vpp v19.08.1-397~g4e34140fa-dirty built by root on buildkitsandbox at Wed Dec 11 15:02:55 UTC 2019")
225   ])
226
227
228pfcpASResp.show2()
229assert bytes(pfcpASResp) == pfcpASRespBytes
230
231pfcpASResp = PFCP(pfcpASRespBytes)
232assert pfcpASResp.version == 1
233assert pfcpASResp.MP == 0
234assert pfcpASResp.S == 0
235assert pfcpASResp.message_type == 6
236assert pfcpASResp.length == 140
237
238ies = pfcpASResp[PFCPAssociationSetupResponse].IE_list
239assert isinstance(ies[0], IE_Cause)
240assert ies[0].ietype == 19
241assert ies[0].length == 1
242assert ies[0].cause == 1
243assert isinstance(ies[1], IE_RecoveryTimeStamp)
244assert ies[1].ietype == 96
245assert ies[1].length == 4
246assert ies[1].timestamp == 3785652985
247assert isinstance(ies[2], IE_UPFunctionFeatures)
248assert ies[2].ietype == 43
249assert ies[2].length == 2
250assert ies[2].TREU == 0
251assert ies[2].HEEU == 0
252assert ies[2].PFDM == 0
253assert ies[2].FTUP == 0
254assert ies[2].TRST == 0
255assert ies[2].DLBD == 0
256assert ies[2].DDND == 0
257assert ies[2].BUCP == 0
258assert ies[2].spare == 0
259assert ies[2].PFDE == 0
260assert ies[2].FRRT == 0
261assert ies[2].TRACE == 0
262assert ies[2].QUOAC == 0
263assert ies[2].UDBC == 0
264assert ies[2].PDIU == 0
265assert ies[2].EMPU == 1
266assert isinstance(ies[3], IE_UserPlaneIPResourceInformation)
267assert ies[3].ASSOSI == 0
268assert ies[3].ASSONI == 1
269assert ies[3].TEIDRI == 2
270assert ies[3].V6 == 0
271assert ies[3].V4 == 1
272assert ies[3].teid_range == 0x80
273assert ies[3].ipv4 == "172.18.1.2"
274assert ies[3].network_instance == b"cp"
275assert isinstance(ies[4], IE_EnterpriseSpecific)
276assert ies[4].ietype == 32770
277assert ies[4].enterprise_id == 18681
278assert ies[4].data == b"vpp v19.08.1-397~g4e34140fa-dirty built by root on buildkitsandbox at Wed Dec 11 15:02:55 UTC 2019"
279
280assert pfcpASResp.answers(pfcpASReq)
281
282# = Build and dissect PFCP Session Establishment Request
283
284pfcpSEReq1Bytes = hex_bytes("2132011300000000000000000000020000030021002c000102006c00040000000200040010002a00010000160007066163636573730003000d002c000101006c00040000000100010038006c000400000002005f000100000200190015000901104c9033ac120102001600030263700014000103003800020002001d00040000006400010057006c000400000001000200350016000706616363657373001700210100001d7065726d6974206f75742069702066726f6d20616e7920746f20616e790014000100003800020001001d00040000fde800510004000000010006001b003e000104002500021000004a00040000003c00510004000000010039000d02ffde7210bf97810aac120101003c0006020465726777")
285
286pfcpSEReq1 = PFCP(version=1, S=1, seq=2, seid=0, spare_oct=0) / \
287  PFCPSessionEstablishmentRequest(IE_list=[
288      IE_CreateFAR(IE_list=[
289          IE_ApplyAction(FORW=1),
290          IE_FAR_Id(id=2),
291          IE_ForwardingParameters(IE_list=[
292              IE_DestinationInterface(interface="Access"),
293              IE_NetworkInstance(instance="access"),
294          ])
295      ]),
296      IE_CreateFAR(IE_list=[
297          IE_ApplyAction(DROP=1),
298          IE_FAR_Id(id=1)
299      ]),
300      IE_CreatePDR(IE_list=[
301          IE_FAR_Id(id=2),
302          IE_OuterHeaderRemoval(header="GTP-U/UDP/IPv4"),
303          IE_PDI(IE_list=[
304              IE_FTEID(V4=1, TEID=0x104c9033, ipv4="172.18.1.2"),
305              IE_NetworkInstance(instance="cp"),
306              IE_SourceInterface(interface="CP-function"),
307          ]),
308          IE_PDR_Id(id=2),
309          IE_Precedence(precedence=100)
310      ]),
311      IE_CreatePDR(IE_list=[
312          IE_FAR_Id(id=1),
313          IE_PDI(IE_list=[
314              IE_NetworkInstance(instance="access"),
315              IE_SDF_Filter(FD=1, flow_description="permit out ip from any to any"),
316              IE_SourceInterface(interface="Access"),
317          ]),
318          IE_PDR_Id(id=1),
319          IE_Precedence(precedence=65000),
320          IE_URR_Id(id=1)
321      ]),
322      IE_CreateURR(IE_list=[
323          IE_MeasurementMethod(EVENT=1),
324          IE_ReportingTriggers(start_of_traffic=1),
325          IE_TimeQuota(quota=60),
326          IE_URR_Id(id=1)
327      ]),
328      IE_FSEID(v4=1, seid=0xffde7210bf97810a, ipv4="172.18.1.1"),
329      IE_NodeId(id_type="FQDN", id="ergw")
330    ])
331
332assert bytes(pfcpSEReq1) == pfcpSEReq1Bytes
333assert bytes(PFCP(pfcpSEReq1Bytes)) == pfcpSEReq1Bytes
334
335pfcpSEReq2Bytes = hex_bytes("213202ba00000000000000000000080000030037002c000102006c00040000000400040026002a000102001600040373676900260015020012687474703a2f2f6578616d706c652e636f6d0003001e002c000102006c0004000000020004000d002a000102001600040373676900030021002c000102006c00040000000300040010002a000100001600070661636365737300030021002c000102006c00040000000100040010002a00010000160007066163636573730001006d006c0004000000040002004b00160007066163636573730017002e0100002a7065726d6974206f75742069702066726f6d203139382e31392e36352e3420746f2061737369676e65640014000100005d0005020ac00000003800020004001d00040000006400510004000000020001006d006c0004000000020002004b00160007066163636573730017002e0100002a7065726d6974206f75742069702066726f6d203139382e31392e36352e3220746f2061737369676e65640014000100005d0005020ac00000003800020002001d0004000000c800510004000000010001006a006c0004000000030002004800160004037367690017002e0100002a7065726d6974206f75742069702066726f6d203139382e31392e36352e3420746f2061737369676e65640014000102005d0005060ac00000003800020003001d00040000006400510004000000020001006a006c0004000000010002004800160004037367690017002e0100002a7065726d6974206f75742069702066726f6d203139382e31392e36352e3220746f2061737369676e65640014000102005d0005060ac00000003800020001001d0004000000c8005100040000000100060013003e000102002500020000005100040000000200060013003e00010200250002000000510004000000010039000d02ffde7210d971c146ac120101003c0006020465726777")
336
337pfcpSEReq2 = PFCP(seq=8) / PFCPSessionEstablishmentRequest(IE_list=[
338    IE_CreateFAR(IE_list=[
339        IE_ApplyAction(FORW=1),
340        IE_FAR_Id(id=4),
341        IE_ForwardingParameters(IE_list=[
342            IE_DestinationInterface(interface="SGi-LAN/N6-LAN"),
343            IE_NetworkInstance(instance="sgi"),
344            IE_RedirectInformation(type="URL", address="http://example.com"),
345        ])
346    ]),
347    IE_CreateFAR(IE_list=[
348        IE_ApplyAction(FORW=1),
349        IE_FAR_Id(id=2),
350        IE_ForwardingParameters(IE_list=[
351            IE_DestinationInterface(interface="SGi-LAN/N6-LAN"),
352            IE_NetworkInstance(instance="sgi"),
353        ])
354    ]),
355    IE_CreateFAR(IE_list=[
356        IE_ApplyAction(FORW=1),
357        IE_FAR_Id(id=3),
358        IE_ForwardingParameters(IE_list=[
359            IE_DestinationInterface(interface="Access"),
360            IE_NetworkInstance(instance="access")
361        ])
362    ]),
363    IE_CreateFAR(IE_list=[
364        IE_ApplyAction(FORW=1),
365        IE_FAR_Id(id=1),
366        IE_ForwardingParameters(IE_list=[
367            IE_DestinationInterface(interface="Access"),
368            IE_NetworkInstance(instance="access")
369        ])
370    ]),
371    IE_CreatePDR(IE_list=[
372        IE_FAR_Id(id=4),
373        IE_PDI(IE_list=[
374            IE_NetworkInstance(instance="access"),
375            IE_SDF_Filter(
376                FD=1, flow_description="permit out ip from 198.19.65.4 to assigned"),
377            IE_SourceInterface(interface="Access"),
378            IE_UE_IP_Address(ipv4="10.192.0.0", V4=1)
379        ]),
380        IE_PDR_Id(id=4),
381        IE_Precedence(precedence=100),
382        IE_URR_Id(id=2)
383    ]),
384    IE_CreatePDR(IE_list=[
385        IE_FAR_Id(id=2),
386        IE_PDI(IE_list=[
387            IE_NetworkInstance(instance="access"),
388            IE_SDF_Filter(FD=1, flow_description="permit out ip from 198.19.65.2 to assigned"),
389            IE_SourceInterface(interface="Access"),
390            IE_UE_IP_Address(ipv4="10.192.0.0", V4=1)
391        ]),
392        IE_PDR_Id(id=2),
393        IE_Precedence(precedence=200),
394        IE_URR_Id(id=1)
395    ]),
396    IE_CreatePDR(IE_list=[
397        IE_FAR_Id(id=3),
398        IE_PDI(IE_list=[
399            IE_NetworkInstance(instance="sgi"),
400            IE_SDF_Filter(FD=1, flow_description="permit out ip from 198.19.65.4 to assigned"),
401            IE_SourceInterface(interface="SGi-LAN/N6-LAN"),
402            IE_UE_IP_Address(ipv4="10.192.0.0", SD=1, V4=1)
403        ]),
404        IE_PDR_Id(id=3),
405        IE_Precedence(precedence=100),
406        IE_URR_Id(id=2)
407    ]),
408    IE_CreatePDR(IE_list=[
409        IE_FAR_Id(id=1),
410        IE_PDI(IE_list=[
411            IE_NetworkInstance(instance="sgi"),
412            IE_SDF_Filter(FD=1, flow_description="permit out ip from 198.19.65.2 to assigned"),
413            IE_SourceInterface(interface="SGi-LAN/N6-LAN"),
414            IE_UE_IP_Address(ipv4="10.192.0.0", SD=1, V4=1)
415        ]),
416        IE_PDR_Id(id=1),
417        IE_Precedence(precedence=200),
418        IE_URR_Id(id=1)
419    ]),
420    IE_CreateURR(IE_list=[
421        IE_MeasurementMethod(VOLUM=1),
422        IE_ReportingTriggers(),
423        IE_URR_Id(id=2)
424    ]),
425    IE_CreateURR(IE_list=[
426        IE_MeasurementMethod(VOLUM=1),
427        IE_ReportingTriggers(),
428        IE_URR_Id(id=1)
429    ]),
430    IE_FSEID(ipv4="172.18.1.1", v4=1, seid=0xffde7210d971c146),
431    IE_NodeId(id_type="FQDN", id="ergw")])
432
433assert bytes(pfcpSEReq2) == pfcpSEReq2Bytes
434assert bytes(PFCP(pfcpSEReq2Bytes)) == pfcpSEReq2Bytes
435
436pfcpSEReq3Bytes = hex_bytes("213203a10000000000000000000003000003001e002c000102006c0004000000060004000d002a000102001600040373676900030037002c000102006c00040000000400040026002a000102001600040373676900260015020012687474703a2f2f6578616d706c652e636f6d0003001e002c000102006c0004000000020004000d002a000102001600040373676900030021002c000102006c00040000000500040010002a000100001600070661636365737300030021002c000102006c00040000000300040010002a000100001600070661636365737300030021002c000102006c00040000000100040010002a000100001600070661636365737300010042006c000400000006000200200018000354535400160007066163636573730014000100005d0005020ac00000003800020006001d00040000009600510004000000030001006d006c0004000000040002004b00160007066163636573730017002e0100002a7065726d6974206f75742069702066726f6d203139382e31392e36352e3420746f2061737369676e65640014000100005d0005020ac00000003800020004001d00040000006400510004000000020001006d006c0004000000020002004b00160007066163636573730017002e0100002a7065726d6974206f75742069702066726f6d203139382e31392e36352e3220746f2061737369676e65640014000100005d0005020ac00000003800020002001d0004000000c800510004000000010001003f006c0004000000050002001d0018000354535400160004037367690014000102005d0005060ac00000003800020005001d00040000009600510004000000030001006a006c0004000000030002004800160004037367690017002e0100002a7065726d6974206f75742069702066726f6d203139382e31392e36352e3420746f2061737369676e65640014000102005d0005060ac00000003800020003001d00040000006400510004000000020001006a006c0004000000010002004800160004037367690017002e0100002a7065726d6974206f75742069702066726f6d203139382e31392e36352e3220746f2061737369676e65640014000102005d0005060ac00000003800020001001d0004000000c8005100040000000100060013003e000102002500020000005100040000000200060013003e000103002500020000005100040000000300060013003e00010200250002000000510004000000010039000d02ffde7211a5ab800aac120101003c0006020465726777")
437
438pfcpSEReq3 = PFCP(seq=3) / \
439  PFCPSessionEstablishmentRequest(IE_list=[
440      IE_CreateFAR(IE_list=[
441          IE_ApplyAction(FORW=1),
442          IE_FAR_Id(id=6),
443          IE_ForwardingParameters(IE_list=[
444              IE_DestinationInterface(interface="SGi-LAN/N6-LAN"),
445              IE_NetworkInstance(instance="sgi")
446          ])
447      ]),
448      IE_CreateFAR(IE_list=[
449          IE_ApplyAction(FORW=1),
450          IE_FAR_Id(id=4),
451          IE_ForwardingParameters(IE_list=[
452              IE_DestinationInterface(interface="SGi-LAN/N6-LAN"),
453              IE_NetworkInstance(instance="sgi"),
454              IE_RedirectInformation(type="URL", address="http://example.com")
455          ])
456      ]),
457      IE_CreateFAR(IE_list=[
458          IE_ApplyAction(FORW=1),
459          IE_FAR_Id(id=2),
460          IE_ForwardingParameters(IE_list=[
461              IE_DestinationInterface(interface="SGi-LAN/N6-LAN"),
462              IE_NetworkInstance(instance="sgi")
463          ])
464      ]),
465      IE_CreateFAR(IE_list=[
466          IE_ApplyAction(FORW=1),
467          IE_FAR_Id(id=5),
468          IE_ForwardingParameters(IE_list=[
469              IE_DestinationInterface(interface="Access"),
470              IE_NetworkInstance(instance="access")
471          ])
472      ]),
473      IE_CreateFAR(IE_list=[
474          IE_ApplyAction(FORW=1),
475          IE_FAR_Id(id=3),
476          IE_ForwardingParameters(IE_list=[
477              IE_DestinationInterface(interface="Access"),
478              IE_NetworkInstance(instance="access")
479          ])
480      ]),
481      IE_CreateFAR(IE_list=[
482          IE_ApplyAction(FORW=1),
483          IE_FAR_Id(id=1),
484          IE_ForwardingParameters(IE_list=[
485              IE_DestinationInterface(interface="Access"),
486              IE_NetworkInstance(instance="access")
487          ])
488      ]),
489      IE_CreatePDR(IE_list=[
490          IE_FAR_Id(id=6),
491          IE_PDI(IE_list=[
492              IE_ApplicationId(id="TST"),
493              IE_NetworkInstance(instance="access"),
494              IE_SourceInterface(interface="Access"),
495              IE_UE_IP_Address(ipv4='10.192.0.0', V4=1)
496          ]),
497          IE_PDR_Id(id=6),
498          IE_Precedence(precedence=150),
499          IE_URR_Id(id=3)
500      ]),
501      IE_CreatePDR(IE_list=[
502          IE_FAR_Id(id=4),
503          IE_PDI(IE_list=[
504              IE_NetworkInstance(instance="access"),
505              IE_SDF_Filter(FD=1, flow_description="permit out ip from 198.19.65.4 to assigned"),
506              IE_SourceInterface(interface="Access"),
507              IE_UE_IP_Address(ipv4='10.192.0.0', V4=1)
508          ]),
509          IE_PDR_Id(id=4),
510          IE_Precedence(precedence=100),
511          IE_URR_Id(id=2)
512      ]),
513      IE_CreatePDR(IE_list=[
514          IE_FAR_Id(id=2),
515          IE_PDI(IE_list=[
516              IE_NetworkInstance(instance="access"),
517              IE_SDF_Filter(FD=1, flow_description="permit out ip from 198.19.65.2 to assigned"),
518              IE_SourceInterface(interface="Access"),
519              IE_UE_IP_Address(ipv4='10.192.0.0', V4=1)
520          ]),
521          IE_PDR_Id(id=2),
522          IE_Precedence(precedence=200),
523          IE_URR_Id(id=1)
524      ]),
525      IE_CreatePDR(IE_list=[
526          IE_FAR_Id(id=5),
527          IE_PDI(IE_list=[
528              IE_ApplicationId(id="TST"),
529              IE_NetworkInstance(instance="sgi"),
530              IE_SourceInterface(interface="SGi-LAN/N6-LAN"),
531              IE_UE_IP_Address(ipv4='10.192.0.0', SD=1, V4=1)
532          ]),
533          IE_PDR_Id(id=5),
534          IE_Precedence(precedence=150),
535          IE_URR_Id(id=3)
536      ]),
537      IE_CreatePDR(IE_list=[
538          IE_FAR_Id(id=3),
539          IE_PDI(IE_list=[
540              IE_NetworkInstance(instance="sgi"),
541              IE_SDF_Filter(FD=1, flow_description="permit out ip from 198.19.65.4 to assigned"),
542              IE_SourceInterface(interface="SGi-LAN/N6-LAN"),
543              IE_UE_IP_Address(ipv4='10.192.0.0', SD=1, V4=1)
544          ]),
545          IE_PDR_Id(id=3),
546          IE_Precedence(precedence=100),
547          IE_URR_Id(id=2)
548      ]),
549      IE_CreatePDR(IE_list=[
550          IE_FAR_Id(id=1),
551          IE_PDI(IE_list=[
552              IE_NetworkInstance(instance="sgi"),
553              IE_SDF_Filter(FD=1, flow_description="permit out ip from 198.19.65.2 to assigned"),
554              IE_SourceInterface(interface="SGi-LAN/N6-LAN"),
555              IE_UE_IP_Address(ipv4='10.192.0.0', SD=1, V4=1)
556          ]),
557          IE_PDR_Id(id=1),
558          IE_Precedence(precedence=200),
559          IE_URR_Id(id=1)
560      ]),
561      IE_CreateURR(IE_list=[
562          IE_MeasurementMethod(VOLUM=1),
563          IE_ReportingTriggers(),
564          IE_URR_Id(id=2)
565      ]),
566      IE_CreateURR(IE_list=[
567          IE_MeasurementMethod(VOLUM=1, DURAT=1),
568          IE_ReportingTriggers(),
569          IE_URR_Id(id=3)
570      ]),
571      IE_CreateURR(IE_list=[
572          IE_MeasurementMethod(VOLUM=1),
573          IE_ReportingTriggers(),
574          IE_URR_Id(id=1)
575      ]),
576      IE_FSEID(ipv4='172.18.1.1', v4=1, seid=0xffde7211a5ab800a),
577      IE_NodeId(id_type="FQDN", id="ergw")
578  ])
579
580assert bytes(pfcpSEReq3) == pfcpSEReq3Bytes
581assert bytes(PFCP(pfcpSEReq3Bytes)) == pfcpSEReq3Bytes
582
583= Build and dissect PFCP Session Establishment Response
584
585pfcpSERespBytes = hex_bytes("21330022ffde7210bf97810a0000020000130001010039000d02ffde7210bf97810aac120102")
586
587pfcpSEResp = PFCP(version=1, S=1, seq=2, seid=0xffde7210bf97810a) / \
588  PFCPSessionEstablishmentResponse(IE_list=[
589      IE_Cause(cause="Request accepted"),
590      IE_FSEID(ipv4="172.18.1.2", v4=1, seid=0xffde7210bf97810a),
591  ])
592
593assert bytes(pfcpSEResp) == pfcpSERespBytes
594assert bytes(PFCP(pfcpSERespBytes)) == pfcpSERespBytes
595assert pfcpSEResp.answers(pfcpSEReq1)
596
597= Build and dissect PFCP Heartbeat Request
598
599pfcpHReqBytes = hex_bytes("2001000c0000030000600004e1a47d08")
600
601pfcpHReq = PFCP(version=1, S=0, seq=3) / \
602  PFCPHeartbeatRequest(IE_list=[
603      IE_RecoveryTimeStamp(timestamp=3785653512)
604  ])
605
606assert bytes(pfcpHReq) == pfcpHReqBytes
607assert bytes(PFCP(pfcpHReqBytes)) == pfcpHReqBytes
608
609# = Build and dissect PFCP Heartbeat Response
610
611pfcpHRespBytes = hex_bytes("2002000c0000030000600004e1a47af9")
612
613pfcpHResp = PFCP(version=1, S=0, seq=3) / \
614  PFCPHeartbeatResponse(IE_list=[
615      IE_RecoveryTimeStamp(timestamp=3785652985)
616  ])
617
618assert bytes(pfcpHResp) == pfcpHRespBytes
619assert bytes(PFCP(pfcpHRespBytes)) == pfcpHRespBytes
620assert pfcpHResp.answers(pfcpHReq)
621
622# = Build and dissect PFCP Session Report Request
623
624pfcpSRReq1Bytes = hex_bytes("21380034ffde7210bf99c00300006b0000270001020050001f00510004000000010068000400000001003f00021000005d0005020ac00001")
625
626pfcpSRReq1 = PFCP(seq=107, version=1, S=1, seid=18437299340760956931) / \
627  PFCPSessionReportRequest(IE_list=[
628      IE_ReportType(USAR=1),
629      IE_UsageReport_SRR(IE_list=[
630          IE_URR_Id(id=1),
631          IE_UR_SEQN(number=1),
632          IE_UsageReportTrigger(START=1),
633          IE_UE_IP_Address(ipv4="10.192.0.1", V4=1)
634      ])
635  ])
636
637assert bytes(pfcpSRReq1) == pfcpSRReq1Bytes
638assert bytes(PFCP(pfcpSRReq1Bytes)) == pfcpSRReq1Bytes
639
640pfcpSRReq2Bytes = hex_bytes("2138008a0ffde7210bf940000000310000270001020050007500510004000000030068000400000018003f00020100004b0004e1b44787004c0004e1b447910042001907000000000000000000000000000000000000000000000000004300040000000a8003000a48f9e1b4479137cbd8008004000a48f9e1b4478737cbd8008005000a48f9e1b4479137cbd800")
641
642pfcpSRReq2 = PFCP(seq=49, seid=1152331208797536256) / \
643  PFCPSessionReportRequest(IE_list=[
644      IE_ReportType(USAR=1),
645      IE_UsageReport_SRR(IE_list=[
646          IE_URR_Id(id=3),
647          IE_UR_SEQN(number=24),
648          IE_UsageReportTrigger(PERIO=1),
649          IE_StartTime(timestamp=3786688391),
650          IE_EndTime(timestamp=3786688401),
651          IE_VolumeMeasurement(
652              DLVOL=1, ULVOL=1, TOVOL=1, total=0, uplink=0, downlink=0),
653          IE_DurationMeasurement(duration=10),
654          IE_EnterpriseSpecific(
655              ietype=32771,
656              enterprise_id=18681,
657              data=b'\xe1\xb4G\x917\xcb\xd8\x00'),
658          IE_EnterpriseSpecific(
659              ietype=32772,
660              enterprise_id=18681,
661              data=b'\xe1\xb4G\x877\xcb\xd8\x00'),
662          IE_EnterpriseSpecific(
663              ietype=32773,
664              enterprise_id=18681,
665              data=b'\xe1\xb4G\x917\xcb\xd8\x00')
666      ])
667  ])
668
669assert bytes(pfcpSRReq2) == pfcpSRReq2Bytes
670assert bytes(PFCP(pfcpSRReq2Bytes)) == pfcpSRReq2Bytes
671
672pfcpSRReq3Bytes = hex_bytes("21380035a2a2aa9ad7f316fd0000010000270001020050002000510004000000010068000400000000003f0003100000005d000502ac100202")
673
674pfcpSRReq3 = PFCP(seq=1, seid=11719116762396169981) / \
675    PFCPSessionReportRequest(IE_list=[
676        IE_ReportType(USAR=1),
677        IE_UsageReport_SRR(IE_list=[
678            IE_URR_Id(id=1),
679            IE_UR_SEQN(number=0),
680            IE_UsageReportTrigger(START=1, extra_data=b'\x00'),
681            IE_UE_IP_Address(ipv4='172.16.2.2', V4=1)
682        ])
683    ])
684
685assert bytes(pfcpSRReq3) == pfcpSRReq3Bytes
686assert bytes(PFCP(pfcpSRReq3Bytes)) == pfcpSRReq3Bytes
687
688= Build and dissect PFCP Session Report Response
689
690pfcpSRRespBytes = hex_bytes("21390011ffde7210bf99c00300006b000013000101")
691
692pfcpSRResp = PFCP(version=1, S=1, seq=107, seid=0xffde7210bf99c003) / \
693  PFCPSessionReportResponse(IE_list=[
694      IE_Cause(cause="Request accepted")
695  ])
696
697assert bytes(pfcpSRResp) == pfcpSRRespBytes
698assert bytes(PFCP(pfcpSRRespBytes)) == pfcpSRRespBytes
699assert pfcpSRResp.answers(pfcpSRReq1)
700
701= Build and dissect PFCP Session Modification Request
702
703pfcpSMReqBytes = hex_bytes("21340018ffde72125aeb00a300000600004d00080051000400000001")
704pfcpSMReq = PFCP(pfcpSMReqBytes)
705
706pfcpSMReq = PFCP(version=1, seq=6, seid=0xffde72125aeb00a3) / \
707    PFCPSessionModificationRequest(IE_list=[
708        IE_QueryURR(IE_list=[IE_URR_Id(id=1)])
709    ])
710assert bytes(pfcpSMReq) == pfcpSMReqBytes
711assert bytes(PFCP(pfcpSMReqBytes)) == pfcpSMReqBytes
712
713= Build and dissect PFCP Session Modification Response
714
715pfcpSMRespBytes = hex_bytes("2135008affde72125aeb00a3000006000013000101004e007500510004000000010068000400000000003f00028000004b0004e16e7efa004c0004e16e7efa004200190700000000000000000000000000000000000000000000000000430004000000008003000a48f9e16e7efa05566c008004000a48f9e16e7efa027f08008005000a48f9e16e7efa027f0800")
716
717pfcpSMResp = PFCP(version=1, seq=6, seid=0xffde72125aeb00a3) / \
718    PFCPSessionModificationResponse(IE_list=[
719        IE_Cause(cause=1),
720        IE_UsageReport_SMR(IE_list=[
721            IE_URR_Id(id=1),
722            IE_UR_SEQN(number=0),
723            IE_UsageReportTrigger(IMMER=1),
724            IE_StartTime(timestamp=3782115066),
725            IE_EndTime(timestamp=3782115066),
726            IE_VolumeMeasurement(DLVOL=1, ULVOL=1, TOVOL=1),
727            IE_DurationMeasurement(),
728            IE_EnterpriseSpecific(ietype=32771, enterprise_id=18681, data=b'\xe1n~\xfa\x05Vl\x00'),
729            IE_EnterpriseSpecific(ietype=32772, enterprise_id=18681, data=b'\xe1n~\xfa\x02\x7f\x08\x00'),
730            IE_EnterpriseSpecific(ietype=32773, enterprise_id=18681, data=b'\xe1n~\xfa\x02\x7f\x08\x00')
731        ])
732    ])
733
734assert bytes(pfcpSMResp) == pfcpSMRespBytes
735assert bytes(PFCP(pfcpSMRespBytes)) == pfcpSMRespBytes
736assert pfcpSMResp.answers(pfcpSMReq)
737
738= Verify IEs
739
740from difflib import unified_diff
741cases = [
742    dict(
743        hex="0054000a0100010000000a177645",
744        expect=IE_OuterHeaderCreation(GTPUUDPIPV4=1, TEID=0x01000000, ipv4="10.23.118.69")),
745    dict(
746        hex="002900050461626364",
747        expect=IE_ForwardingPolicy(policy_identifier="abcd")),
748    dict(
749        hex="002e0001ae",
750        expect=IE_DownlinkDataNotificationDelay(delay=174)),
751    dict(
752        hex="003d00020000",
753        expect=IE_PFDContents()),
754    dict(
755        hex="005e00070300205903e95d",
756        expect=IE_PacketRate(ULPR=1, DLPR=1,
757                             ul_time_unit="minute", ul_max_packet_rate=8281,
758                             dl_time_unit="day", dl_max_packet_rate=59741)),
759    dict(
760        hex="00850007010906638dccd5",
761        expect=IE_MACAddress(SOUR=1, source_mac="09:06:63:8d:cc:d5")),
762    dict(
763        hex="00540014080017d0bd69dceb747a1e036c0f9c8d4af115d0",
764        expect=IE_OuterHeaderCreation(UDPIPV6=1,
765                                      ipv6="17d0:bd69:dceb:747a:1e03:6c0f:9c8d:4af1",
766                                      port=5584)),
767    dict(
768        hex="006700050280df69b2",
769        expect=IE_RemoteGTP_U_Peer(V4=1, ipv4="128.223.105.178")),
770]
771
772for case in cases:
773    bs = hex_bytes(case["hex"])
774    exp = case["expect"]
775    dissected = type(exp)(bs)
776    exp_text = exp.show2(dump=True)
777    dissected_text = dissected.show2(dump=True)
778    if exp_text != dissected_text:
779        print("---\n%s\n---\n%s\n" % (exp_text, dissected_text))
780        for line in unified_diff(exp_text.split("\n"), dissected_text.split("\n"),
781                                 fromfile="expected", tofile="dissected"):
782            print(line)
783        raise AssertionError("text mismatch")
784    assert bytes(dissected) == bs
785    assert bytes(exp) == bs
786
787# from difflib import unified_diff
788# expected = PFCP(pfcpSRReq2Bytes).show2(dump=True).split("\n")
789# actual = pfcpSRReq2.show2(dump=True).split("\n")
790# for line in unified_diff(expected, actual, fromfile="expected", tofile="actual"):
791#     print(line)
792