Complete IGMPv3 membership report
Change-Id: I900478972675ee60928b39bbdc55858d3bea998b
diff --git a/IGMP.py b/IGMP.py
index a747d09..1b24de3 100644
--- a/IGMP.py
+++ b/IGMP.py
@@ -25,6 +25,36 @@
IGMP_SRC_MAC = "5a:e1:ac:ec:4d:a1"
"""
+
+class IGMPv3gr(Packet):
+ """IGMPv3 Group Record, used in membership report"""
+
+ name = "IGMPv3gr"
+
+ igmp_v3_gr_types = {
+ IGMP_V3_GR_TYPE_INCLUDE: "Include Mode",
+ IGMP_V3_GR_TYPE_EXCLUDE: "Exclude Mode",
+ IGMP_V3_GR_TYPE_CHANGE_TO_INCLUDE: "Change to Include Mode",
+ IGMP_V3_GR_TYPE_CHANGE_TO_EXCLUDE: "Change to Exclude Mode",
+ IGMP_V3_GR_TYPE_ALLOW_NEW: "Allow New Sources",
+ IGMP_V3_GR_TYPE_BLOCK_OLD: "Block Old Sources"
+ }
+
+ fields_desc = [
+ ByteEnumField("rtype", IGMP_V3_GR_TYPE_INCLUDE, igmp_v3_gr_types),
+ ByteField("aux_data_len", 0),
+ FieldLenField("numsrc", None, count_of="sources"),
+ IPField("mcaddr", "0.0.0.0"),
+ FieldListField("sources", None, IPField("src", "0.0.0.0"), "numsrc")
+ ]
+
+ def post_build(self, pkt, payload):
+ pkt += payload
+ if self.aux_data_len != 0:
+ print "WARNING: Auxiliary Data Length must be zero (0)"
+ return pkt
+
+
class IGMPv3(Packet):
name = "IGMPv3"
@@ -50,10 +80,14 @@
ConditionalField(BitField("qrv", 0, 3), lambda pkt: pkt.type == IGMP_TYPE_MEMBERSHIP_QUERY),
ConditionalField(ByteField("qqic", 0), lambda pkt: pkt.type == IGMP_TYPE_MEMBERSHIP_QUERY),
ConditionalField(FieldLenField("numsrc", None, count_of="srcs"), lambda pkt: pkt.type == IGMP_TYPE_MEMBERSHIP_QUERY),
- ConditionalField(FieldListField("srcs", None, IPField("src", "0.0.0.0"), "numsrc"), lambda pkt: pkt.type == IGMP_TYPE_MEMBERSHIP_QUERY)
+ ConditionalField(FieldListField("srcs", None, IPField("src", "0.0.0.0"), "numsrc"), lambda pkt: pkt.type == IGMP_TYPE_MEMBERSHIP_QUERY),
# membership report fields
- # TODO
+ ConditionalField(ShortField("resv2", 0), lambda pkt: pkt.type == IGMP_TYPE_V3_MEMBERSHIP_REPORT),
+ ConditionalField(FieldLenField("numgrp", None, count_of="grps"), lambda pkt: pkt.type == IGMP_TYPE_V3_MEMBERSHIP_REPORT),
+ ConditionalField(PacketListField("grps", [], IGMPv3gr), lambda pkt: pkt.type == IGMP_TYPE_V3_MEMBERSHIP_REPORT)
+
+ # TODO: v2 and v3 membership reports?
]
@@ -138,34 +172,6 @@
return pkt
-class IGMPv3gr(Packet):
-
- name = "IGMPv3gr"
-
- igmp_v3_gr_types = {
- IGMP_V3_GR_TYPE_INCLUDE: "Include Mode",
- IGMP_V3_GR_TYPE_EXCLUDE: "Exclude Mode",
- IGMP_V3_GR_TYPE_CHANGE_TO_INCLUDE: "Change to Include Mode",
- IGMP_V3_GR_TYPE_CHANGE_TO_EXCLUDE: "Change to Exclude Mode",
- IGMP_V3_GR_TYPE_ALLOW_NEW: "Allow New Sources",
- IGMP_V3_GR_TYPE_BLOCK_OLD: "Block Old Sources"
- }
-
- fields_desc = [
- ByteEnumField("rtype", IGMP_V3_GR_TYPE_INCLUDE, igmp_v3_gr_types),
- ByteField("aux_data_len", 0),
- FieldLenField("numsrc", None, "sources"),
- IPField("mcast_addr", "0.0.0.0"),
- FieldListField("sources", None, IPField("src", "0.0.0.0"), "numsrc")
- ]
-
- def post_build(self, pkt, payload):
- pkt += payload
- if self.aux_data_len != 0:
- print "WARNING: Auxiliary Data Length must be zero (0)"
- return pkt
-
-
bind_layers(IP, IGMPv3, frag=0, proto=2, ttl=1, tos=0xc0)
bind_layers(IGMPv3, IGMPv3gr, frag=0, proto=2)
bind_layers(IGMPv3gr, IGMPv3gr, frag=0, proto=2)
@@ -207,4 +213,22 @@
IGMPv3.fixup(pkt)
hexdump(str(pkt))
+ print "construct v3 membership report - join a single group"
+ mr = IGMPv3(type=IGMP_TYPE_V3_MEMBERSHIP_REPORT, max_resp_code=30, gaddr="224.0.0.1")
+ mr.grps = [IGMPv3gr( rtype=IGMP_V3_GR_TYPE_EXCLUDE, mcaddr="229.10.20.30")]
+ hexdump(mr)
+
+ print "construct v3 membership report - join two groups"
+ mr = IGMPv3(type=IGMP_TYPE_V3_MEMBERSHIP_REPORT, max_resp_code=30, gaddr="224.0.0.1")
+ mr.grps = [
+ IGMPv3gr(rtype=IGMP_V3_GR_TYPE_EXCLUDE, mcaddr="229.10.20.30"),
+ IGMPv3gr(rtype=IGMP_V3_GR_TYPE_EXCLUDE, mcaddr="229.10.20.31")
+ ]
+ hexdump(mr)
+
+ print "construct v3 membership report - leave a group"
+ mr = IGMPv3(type=IGMP_TYPE_V3_MEMBERSHIP_REPORT, max_resp_code=30, gaddr="224.0.0.1")
+ mr.grps = [IGMPv3gr(rtype=IGMP_V3_GR_TYPE_INCLUDE, mcaddr="229.10.20.30")]
+ hexdump(mr)
+
print "all ok"
diff --git a/olt.py b/olt.py
index a8e26c4..4f78f2a 100644
--- a/olt.py
+++ b/olt.py
@@ -14,7 +14,8 @@
from oftest.testutils import *
-from IGMP import IGMPv3
+from IGMP import IGMPv3, IGMPv3gr, IGMP_TYPE_V3_MEMBERSHIP_REPORT, IGMP_V3_GR_TYPE_INCLUDE
+
# These parameters can be altered from the command line using the -t or --test-params= options.
# Example: -t 'onu_port=129;olt_port=288;device_type=pmc'
@@ -171,9 +172,9 @@
match.oxm_list.append(ofp.oxm.eth_type(0x800))
match.oxm_list.append(ofp.oxm.ip_proto(2))
- pkt = scapy.Ether(dst='01:00:5E:7F:FF:FF', src='00:00:00:00:00:01')/ \
- scapy.IP(src='10.0.0.1', dst='10.0.0.2', ttl=60, tos=0, id=0, proto=2)
-
+ igmp = IGMPv3(type=IGMP_TYPE_V3_MEMBERSHIP_REPORT, max_resp_code=30, gaddr="224.0.0.1")
+ igmp.grps = [IGMPv3gr(rtype=IGMP_V3_GR_TYPE_INCLUDE, mcaddr="229.10.20.30")]
+ pkt = IGMPv3.fixup( scapy.Ether(src='00:00:00:00:be:ef') / scapy.IP() / igmp )
pkt = pkt / ("0" * (100 - len(pkt)))
testPacketIn(self, match, pkt)