Skip to content

Commit

Permalink
Merge pull request #225 from GabrielGanne/nsh-update
Browse files Browse the repository at this point in the history
NSH: first implementation and small update
  • Loading branch information
guedou committed Aug 24, 2016
2 parents 5b5bd11 + dbeb275 commit 7365c97
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 8 deletions.
79 changes: 79 additions & 0 deletions scapy/contrib/nsh.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#! /usr/bin/env python
# scapy.contrib.description = nsh
# scapy.contrib.status = loads
from scapy.all import bind_layers
from scapy.fields import BitField, ByteField, ByteEnumField
from scapy.fields import ShortField, X3BytesField, XIntField
from scapy.fields import ConditionalField, PacketListField
from scapy.layers.inet import Ether, IP
from scapy.layers.inet6 import IPv6
from scapy.layers.vxlan import VXLAN
from scapy.packet import Packet

from scapy.contrib.mpls import MPLS

#
# NSH Support
# https://www.ietf.org/id/draft-ietf-sfc-nsh-05.txt
#


class Metadata(Packet):
name = 'NSH metadata'
fields_desc = [XIntField('value', 0)]


class NSHTLV(Packet):
"NSH MD-type 2 - Variable Length Context Headers"
name = "NSHTLV"
fields_desc = [
ShortField('Class', 0),
BitField('Critical', 0, 1),
BitField('Type', 0, 7),
BitField('Reserved', 0, 3),
BitField('Len', 0, 5),
PacketListField('Metadata', None, XIntField, count_from='Len')
]


class NSH(Packet):
"""Network Service Header.
NSH MD-type 1 if there is no ContextHeaders"""
name = "NSH"

fields_desc = [
BitField('Ver', 0, 2),
BitField('OAM', 0, 1),
BitField('Critical', 0, 1),
BitField('Reserved', 0, 6),
BitField('Len', 0, 6),
ByteEnumField('MDType', 1, {1: 'Fixed Length',
2: 'Variable Length'}),
ByteEnumField('NextProto', 3, {1: 'IPv4',
2: 'IPv6',
3: 'Ethernet',
4: 'NSH',
5: 'MPLS'}),
X3BytesField('NSP', 0),
ByteField('NSI', 1),
ConditionalField(XIntField('NPC', 0), lambda pkt: pkt.MDType == 1),
ConditionalField(XIntField('NSC', 0), lambda pkt: pkt.MDType == 1),
ConditionalField(XIntField('SPC', 0), lambda pkt: pkt.MDType == 1),
ConditionalField(XIntField('SSC', 0), lambda pkt: pkt.MDType == 1),
ConditionalField(PacketListField("ContextHeaders", None,
NSHTLV, count_from="Length"),
lambda pkt: pkt.MDType == 2)
]

def mysummary(self):
return self.sprintf("NSP: %NSP% - NSI: %NSI%")


bind_layers(Ether, NSH, {'type': 0x894F}, type=0x894F)
bind_layers(VXLAN, NSH, {'flags': 0xC, 'NextProtocol': 4}, NextProtocol=4)

bind_layers(NSH, IP, {'NextProto': 1}, NextProto=1)
bind_layers(NSH, IPv6, {'NextProto': 2}, NextProto=2)
bind_layers(NSH, Ether, {'NextProto': 3}, NextProto=3)
bind_layers(NSH, NSH, {'NextProto': 4}, NextProto=4)
bind_layers(NSH, MPLS, {'NextProto': 5}, NextProto=5)
14 changes: 14 additions & 0 deletions scapy/contrib/nsh.uts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
% NSH Tests
* Tests for the Scapy NSH layer

+ Syntax check
= Import the nsh layer
from scapy.contrib.nsh import *

+ Basic Layer Tests

= Build a NSH over NSH packet with NSP=42, and NSI=1
str(NSH(Len=2, NSP=42, NSI=1)/NSH()) == '\x00\x02\x01\x04\x00\x00*\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x03\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

= Build a Ethernet over NSH over Ethernet packet (NSH over Ethernet encapsulating the original packet) and verify Ethernet Bindings
str(Ether(src="00:00:00:00:00:01", dst="00:00:00:00:00:02")/NSH()/Ether(src="00:00:00:00:00:03", dst="00:00:00:00:00:04")/ARP(psrc="10.0.0.1", hwsrc="00:00:00:00:00:01")) == '\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x01\x89O\x00\x00\x01\x03\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x03\x08\x06\x00\x01\x08\x00\x06\x04\x00\x01\x00\x00\x00\x00\x00\x01\n\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
27 changes: 21 additions & 6 deletions scapy/layers/vxlan.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,35 @@
#! /usr/bin/env python
# RFC 7348 - Virtual eXtensible Local Area Network (VXLAN):
# A Framework for Overlaying Virtualized Layer 2 Networks over Layer 3 Networks
# http://tools.ietf.org/html/rfc7348
# https://www.ietf.org/id/draft-ietf-nvo3-vxlan-gpe-02.txt
#
# VXLAN Group Policy Option:
# http://tools.ietf.org/html/draft-smith-vxlan-group-policy-00

from scapy.packet import Packet, bind_layers
from scapy.layers.l2 import Ether
from scapy.layers.inet import UDP
from scapy.layers.inet import IP, UDP
from scapy.layers.inet6 import IPv6
from scapy.fields import FlagsField, XByteField, ThreeBytesField, \
ConditionalField, ShortField
ConditionalField, ShortField, ByteEnumField, X3BytesField

_VXLAN_FLAGS = ["R", "R", "R", "I", "R", "R", "R", "G"]
_GP_FLAGS = ["R", "R", "R", "A", "R", "R", "D", "R"]


class VXLAN(Packet):
name = "VXLAN"

fields_desc = [
FlagsField("flags", 0x8, 8, _VXLAN_FLAGS),
FlagsField("flags", 0x8, 8,
['OAM', 'R', 'NextProtocol', 'Instance',
'V1', 'V2', 'R', 'G']),
ByteEnumField('NextProtocol', 0,
{0: 'NotDefined',
1: 'IPv4',
2: 'IPv6',
3: 'Ethernet',
4: 'NSH'}),
ConditionalField(
ThreeBytesField("reserved1", 0x000000),
lambda pkt: not pkt.flags & 0x80,
Expand All @@ -31,7 +42,7 @@ class VXLAN(Packet):
ShortField("gpid", 0),
lambda pkt: pkt.flags & 0x80,
),
ThreeBytesField("vni", 0),
X3BytesField("vni", 0),
XByteField("reserved2", 0x00),
]

Expand All @@ -47,5 +58,9 @@ def mysummary(self):
return self.sprintf("VXLAN (vni=%VXLAN.vni%)")

bind_layers(UDP, VXLAN, dport=4789) # RFC standard port
bind_layers(UDP, VXLAN, dport=6633) # New IANA assigned port when used with NSH
bind_layers(UDP, VXLAN, dport=8472) # Linux implementation port
bind_layers(VXLAN, Ether)
bind_layers(VXLAN, Ether, {'flags': 0x8}, NextProtocol=0)
bind_layers(VXLAN, IP, {'flags': 0xC, 'NextProtocol': 1}, NextProtocol=1)
bind_layers(VXLAN, IPv6, {'flags': 0xC, 'NextProtocol': 2}, NextProtocol=2)
bind_layers(VXLAN, Ether, {'flags': 0xC, 'NextProtocol': 3}, NextProtocol=3)
4 changes: 2 additions & 2 deletions test/regression.uts
Original file line number Diff line number Diff line change
Expand Up @@ -6123,10 +6123,10 @@ assert(p.data[0].ifname.startswith("lo"))
+ VXLAN layer

= Build a VXLAN packet with VNI of 42
str(UDP(sport=1024, dport=4789, len=None, chksum=None)/VXLAN(flags=0x08, vni=42)) == "\x04\x00\x12\xb5\x00\x10\x00\x00\x08\x00\x00\x00\x00\x00\x2a\x00"
str(UDP(sport=1024, dport=4789, len=None, chksum=None)/VXLAN(flags=0x08, vni=42)) == '\x04\x00\x12\xb5\x00\x11\x00\x00\x08\x00\x00\x00\x00\x00\x00\x2a\x00'

= Verify VXLAN Ethernet Binding
str(VXLAN(vni=23)/Ether(dst="11:11:11:11:11:11", src="11:11:11:11:11:11", type=0x800)) == "\x08\x00\x00\x00\x00\x00\x17\x00\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x08\x00"
str(VXLAN(vni=23)/Ether(dst="11:11:11:11:11:11", src="11:11:11:11:11:11", type=0x800)) == '\x0c\x03\x00\x00\x00\x00\x00\x17\x00\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x08\x00'

= Verify UDP dport overloading
p = Ether(dst="11:11:11:11:11:11", src="22:22:22:22:22:22")
Expand Down

0 comments on commit 7365c97

Please sign in to comment.