Skip to content

Commit fe4bc55

Browse files
alexaringgpotter2
authored andcommitted
scapy: contrib: ife: initial commit (#1810)
* scapy: contrib: ife: initial commit This patch add the IFE ethertype as defined in RFC 8013 (https://tools.ietf.org/html/rfc8013). This has been tested with the Linux implementation as described in https://www.netdevconf.org/0.1/sessions/9.html The code is somehow based by looking up some other ethernet based payload as lldp. * scapy: contrib: ife: add testcases
1 parent b2eef19 commit fe4bc55

File tree

2 files changed

+159
-0
lines changed

2 files changed

+159
-0
lines changed

scapy/contrib/ife.py

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#! /usr/bin/env python
2+
#
3+
# scapy.contrib.description = ForCES Inter-FE LFB type (IFE)
4+
# scapy.contrib.status = loads
5+
6+
"""
7+
IFE - ForCES Inter-FE LFB type
8+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9+
10+
:author: Alexander Aring, aring@mojatatu.com
11+
:license: GPLv2
12+
13+
This module is free software; you can redistribute it and/or
14+
modify it under the terms of the GNU General Public License
15+
as published by the Free Software Foundation; either version 2
16+
of the License, or (at your option) any later version.
17+
18+
This module is distributed in the hope that it will be useful,
19+
but WITHOUT ANY WARRANTY; without even the implied warranty of
20+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21+
GNU General Public License for more details.
22+
23+
:description:
24+
25+
This module provides Scapy layers for the IFE protocol.
26+
27+
normative references:
28+
- RFC 8013
29+
Forwarding and Control Element Separation (ForCES)
30+
Inter-FE Logical Functional Block (LFB)
31+
https://tools.ietf.org/html/rfc8013
32+
"""
33+
34+
import functools
35+
36+
from scapy.data import ETHER_TYPES
37+
from scapy.packet import Packet, bind_layers
38+
from scapy.fields import FieldLenField, PacketListField, IntField, \
39+
MultipleTypeField, ShortField, ShortEnumField, StrField, PadField
40+
from scapy.layers.l2 import Ether
41+
42+
ETH_P_IFE = 0xed3e
43+
ETHER_TYPES['IFE'] = ETH_P_IFE
44+
45+
# The value to set for the skb mark.
46+
IFE_META_SKBMARK = 0x0001
47+
IFE_META_HASHID = 0x0002
48+
# Value to set for priority in the skb structure.
49+
IFE_META_PRIO = 0x0003
50+
IFE_META_QMAP = 0x0004
51+
# Value to set for the traffic control index in the skb structure.
52+
IFE_META_TCINDEX = 0x0005
53+
54+
IFE_META_TYPES = {
55+
IFE_META_SKBMARK: "SKBMark",
56+
IFE_META_HASHID: "HashID",
57+
IFE_META_PRIO: "Prio",
58+
IFE_META_QMAP: "QMap",
59+
IFE_META_TCINDEX: "TCIndex"
60+
}
61+
62+
IFE_TYPES_SHORT = [IFE_META_TCINDEX]
63+
IFE_TYPES_INT = [
64+
IFE_META_SKBMARK,
65+
IFE_META_PRIO,
66+
]
67+
68+
69+
class IFETlv(Packet):
70+
"""
71+
Parent Class interhit by all ForCES TLV strucutures
72+
"""
73+
name = "IFETlv"
74+
75+
fields_desc = [
76+
ShortEnumField("type", 0, IFE_META_TYPES),
77+
FieldLenField("length", None, length_of="value",
78+
adjust=lambda pkt, x: x + 4),
79+
MultipleTypeField(
80+
[
81+
(PadField(ShortField("value", 0), 4, padwith=b'\x00'),
82+
lambda pkt: pkt.type in IFE_TYPES_SHORT),
83+
(PadField(IntField("value", 0), 4, padwith=b'\x00'),
84+
lambda pkt: pkt.type in IFE_TYPES_INT),
85+
],
86+
PadField(IntField("value", 0), 4, padwith=b'\x00')
87+
),
88+
]
89+
90+
def extract_padding(self, s):
91+
return "", s
92+
93+
94+
class IFETlvStr(IFETlv):
95+
"""
96+
A IFE TLV with variable payload
97+
"""
98+
fields_desc = [
99+
ShortEnumField("type", 0, IFE_META_TYPES),
100+
FieldLenField("length", None, length_of="value",
101+
adjust=lambda pkt, x: x + 4),
102+
StrField("value", "")
103+
]
104+
105+
106+
class IFE(Packet):
107+
"""
108+
Main IFE Packet Class
109+
"""
110+
name = "IFE"
111+
112+
fields_desc = [
113+
FieldLenField("mdlen", None, length_of="tlvs",
114+
adjust=lambda pkt, x: x + 2),
115+
PacketListField("tlvs", None, IFETlv),
116+
]
117+
118+
119+
IFESKBMark = functools.partial(IFETlv, type=IFE_META_SKBMARK)
120+
IFEHashID = functools.partial(IFETlv, type=IFE_META_HASHID)
121+
IFEPrio = functools.partial(IFETlv, type=IFE_META_PRIO)
122+
IFEQMap = functools.partial(IFETlv, type=IFE_META_QMAP)
123+
IFETCIndex = functools.partial(IFETlv, type=IFE_META_TCINDEX)
124+
125+
bind_layers(Ether, IFE, type=ETH_P_IFE)

test/contrib/ife.uts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
% IFE test campaign
2+
3+
#
4+
# execute test:
5+
# > test/run_tests -P "load_contrib('ife')" -t test/contrib/ife.uts
6+
#
7+
8+
+ Basic layer handling
9+
= build basic IFE frames
10+
11+
frm = Ether()/IFE(tlvs=[IFESKBMark(value=3), IFETCIndex(value=5)])
12+
13+
frm = Ether(bytes(frm))
14+
15+
assert(IFE in frm)
16+
assert(frm[IFE].tlvs[0].type == 1)
17+
assert(frm[IFE].tlvs[0].length == 8)
18+
assert(frm[IFE].tlvs[0].value == 3)
19+
assert(frm[IFE].tlvs[1].type == 5)
20+
assert(frm[IFE].tlvs[1].length == 6)
21+
assert(frm[IFE].tlvs[1].value == 5)
22+
23+
= add padding if required
24+
25+
frm = Ether()/IFE(tlvs=[IFETCIndex()])
26+
assert(len(raw(frm)) == 24)
27+
28+
frm = Ether()/IFE(tlvs=[IFESKBMark(), IFETCIndex()])
29+
assert(len(raw(frm)) == 32)
30+
31+
= variable payload
32+
33+
frm = Ether(src="aa:aa:aa:aa:aa:aa", dst="bb:bb:bb:bb:bb:bb")/IFE(tlvs=[IFETlvStr("testsr")])
34+
assert bytes(frm) == b'\xbb\xbb\xbb\xbb\xbb\xbb\xaa\xaa\xaa\xaa\xaa\xaa\xed>\x00\x08testsr'

0 commit comments

Comments
 (0)