blob: 15aafb1b3798655fc5d1e028b9b7501e8d093c4e [file] [log] [blame]
Arjun E K57a7fcb2020-01-30 06:44:45 +00001/*
2 * Copyright 2018-present Open Networking Foundation
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 * http://www.apache.org/licenses/LICENSE-2.0
7 * Unless required by applicable law or agreed to in writing, software
8 * distributed under the License is distributed on an "AS IS" BASIS,
9 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 * See the License for the specific language governing permissions and
11 * limitations under the License.
12 */
13
14package igmp
15
16import (
17 "encoding/binary"
Matteo Scandolo618a6582020-09-09 12:21:29 -070018 "encoding/hex"
19 "errors"
20 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
Anand S Katti09541352020-01-29 15:54:01 +053021 "net"
22 "time"
23
Arjun E K57a7fcb2020-01-30 06:44:45 +000024 "github.com/google/gopacket"
25 "github.com/google/gopacket/layers"
26 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070027 "github.com/opencord/voltha-protos/v4/go/openolt"
Arjun E K57a7fcb2020-01-30 06:44:45 +000028 log "github.com/sirupsen/logrus"
Arjun E K57a7fcb2020-01-30 06:44:45 +000029)
30
Matteo Scandolo618a6582020-09-09 12:21:29 -070031func SendIGMPLeaveGroupV2(ponPortId uint32, onuId uint32, serialNumber string, portNo uint32,
Onur Kalinagac9f9faca2021-01-21 14:04:34 +000032 gemPortId uint32, macAddress net.HardwareAddr, cTag int, pbit uint8, stream bbsim.Stream, groupAddress string) error {
Arjun E K57a7fcb2020-01-30 06:44:45 +000033 log.WithFields(log.Fields{
34 "OnuId": onuId,
35 "SerialNumber": serialNumber,
36 "PortNo": portNo,
Onur Kalinagac9f9faca2021-01-21 14:04:34 +000037 "GroupAddress": groupAddress,
Arjun E K57a7fcb2020-01-30 06:44:45 +000038 }).Debugf("Entered SendIGMPLeaveGroupV2")
Onur Kalinagac9f9faca2021-01-21 14:04:34 +000039 igmp := createIGMPV2LeaveRequestPacket(groupAddress)
Matteo Scandolo618a6582020-09-09 12:21:29 -070040 pkt, err := serializeIgmpPacket(ponPortId, onuId, cTag, macAddress, pbit, igmp)
Arjun E K57a7fcb2020-01-30 06:44:45 +000041
42 if err != nil {
43 log.WithFields(log.Fields{
44 "OnuId": onuId,
45 "IntfId": ponPortId,
46 "SerialNumber": serialNumber,
Onur Kalinagac9f9faca2021-01-21 14:04:34 +000047 "GroupAddress": groupAddress,
Arjun E K57a7fcb2020-01-30 06:44:45 +000048 }).Errorf("Seriliazation of igmp packet failed : %s", err)
49 return err
50 }
51
Arjun E K57a7fcb2020-01-30 06:44:45 +000052 data := &openolt.Indication_PktInd{
53 PktInd: &openolt.PacketIndication{
54 IntfType: "pon",
55 IntfId: ponPortId,
Matteo Scandolo618a6582020-09-09 12:21:29 -070056 GemportId: gemPortId,
Arjun E K57a7fcb2020-01-30 06:44:45 +000057 Pkt: pkt,
58 PortNo: portNo,
59 },
60 }
61 //Sending IGMP packets
62 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
Matteo Scandolo583f17d2020-02-13 10:35:17 -080063 log.WithFields(log.Fields{
64 "OnuId": onuId,
65 "SerialNumber": serialNumber,
66 "PortNo": portNo,
67 "IntfId": ponPortId,
Onur Kalinagac9f9faca2021-01-21 14:04:34 +000068 "GroupAddress": groupAddress,
Matteo Scandolo583f17d2020-02-13 10:35:17 -080069 "err": err,
70 }).Error("Fail to send IGMP PktInd indication for ONU")
Arjun E K57a7fcb2020-01-30 06:44:45 +000071 return err
72 }
73 return nil
74}
75
Matteo Scandolo618a6582020-09-09 12:21:29 -070076func SendIGMPMembershipReportV2(ponPortId uint32, onuId uint32, serialNumber string, portNo uint32,
Onur Kalinagac9f9faca2021-01-21 14:04:34 +000077 gemPortId uint32, macAddress net.HardwareAddr, cTag int, pbit uint8, stream bbsim.Stream, groupAddress string) error {
Matteo Scandolo618a6582020-09-09 12:21:29 -070078
Onur Kalinagac9f9faca2021-01-21 14:04:34 +000079 igmp := createIGMPV2MembershipReportPacket(groupAddress)
Matteo Scandolo618a6582020-09-09 12:21:29 -070080 pkt, err := serializeIgmpPacket(ponPortId, onuId, cTag, macAddress, pbit, igmp)
Arjun E K57a7fcb2020-01-30 06:44:45 +000081
82 if err != nil {
83 log.WithFields(log.Fields{
84 "OnuId": onuId,
85 "IntfId": ponPortId,
86 "SerialNumber": serialNumber,
Onur Kalinagac9f9faca2021-01-21 14:04:34 +000087 "GroupAddress": groupAddress,
Arjun E K57a7fcb2020-01-30 06:44:45 +000088 }).Errorf("Seriliazation of igmp packet failed : %s", err)
89 return err
90 }
91
Arjun E K57a7fcb2020-01-30 06:44:45 +000092 data := &openolt.Indication_PktInd{
93 PktInd: &openolt.PacketIndication{
94 IntfType: "pon",
95 IntfId: ponPortId,
Matteo Scandolo618a6582020-09-09 12:21:29 -070096 GemportId: gemPortId,
Arjun E K57a7fcb2020-01-30 06:44:45 +000097 Pkt: pkt,
98 PortNo: portNo,
99 },
100 }
101 //Sending IGMP packets
102 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
Matteo Scandolo583f17d2020-02-13 10:35:17 -0800103 log.WithFields(log.Fields{
104 "OnuId": onuId,
105 "SerialNumber": serialNumber,
106 "PortNo": portNo,
107 "IntfId": ponPortId,
Onur Kalinagac9f9faca2021-01-21 14:04:34 +0000108 "GroupAddress": groupAddress,
Matteo Scandolo583f17d2020-02-13 10:35:17 -0800109 "err": err,
110 }).Errorf("Fail to send IGMP PktInd indication")
Arjun E K57a7fcb2020-01-30 06:44:45 +0000111 return err
112 }
Matteo Scandolo618a6582020-09-09 12:21:29 -0700113
114 log.WithFields(log.Fields{
115 "OnuId": onuId,
116 "SerialNumber": serialNumber,
117 "PortNo": portNo,
Onur Kalinagac9f9faca2021-01-21 14:04:34 +0000118 "GroupAddress": groupAddress,
Matteo Scandolo618a6582020-09-09 12:21:29 -0700119 }).Debugf("Sent SendIGMPMembershipReportV2")
Arjun E K57a7fcb2020-01-30 06:44:45 +0000120 return nil
121}
122
Matteo Scandolo618a6582020-09-09 12:21:29 -0700123func SendIGMPMembershipReportV3(ponPortId uint32, onuId uint32, serialNumber string, portNo uint32,
Onur Kalinagac9f9faca2021-01-21 14:04:34 +0000124 gemPortId uint32, macAddress net.HardwareAddr, cTag int, pbit uint8, stream bbsim.Stream, groupAddress string) error {
125
Anand S Katti09541352020-01-29 15:54:01 +0530126 log.WithFields(log.Fields{
127 "OnuId": onuId,
128 "SerialNumber": serialNumber,
129 "PortNo": portNo,
Onur Kalinagac9f9faca2021-01-21 14:04:34 +0000130 "GroupAddress": groupAddress,
Anand S Katti09541352020-01-29 15:54:01 +0530131 }).Debugf("Entered SendIGMPMembershipReportV3")
Onur Kalinagac9f9faca2021-01-21 14:04:34 +0000132 igmp := createIGMPV3MembershipReportPacket(groupAddress)
Matteo Scandolo618a6582020-09-09 12:21:29 -0700133 pkt, err := serializeIgmpPacket(ponPortId, onuId, cTag, macAddress, pbit, igmp)
Arjun E Kdd443f02020-02-07 15:24:01 +0000134
Anand S Katti09541352020-01-29 15:54:01 +0530135 if err != nil {
136 log.WithFields(log.Fields{
137 "OnuId": onuId,
138 "IntfId": ponPortId,
139 "SerialNumber": serialNumber,
Onur Kalinagac9f9faca2021-01-21 14:04:34 +0000140 "GroupAddress": groupAddress,
Anand S Katti09541352020-01-29 15:54:01 +0530141 }).Errorf("Seriliazation of igmp packet failed : %s", err)
142 return err
143 }
Arjun E Kdd443f02020-02-07 15:24:01 +0000144
Anand S Katti09541352020-01-29 15:54:01 +0530145 data := &openolt.Indication_PktInd{
146 PktInd: &openolt.PacketIndication{
147 IntfType: "pon",
148 IntfId: ponPortId,
Matteo Scandolo618a6582020-09-09 12:21:29 -0700149 GemportId: gemPortId,
Anand S Katti09541352020-01-29 15:54:01 +0530150 Pkt: pkt,
151 PortNo: portNo,
152 },
153 }
154 //Sending IGMP packets
155 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
Matteo Scandolo446fc9e2020-03-13 15:48:13 -0700156 log.WithFields(log.Fields{
157 "OnuId": onuId,
158 "IntfId": ponPortId,
159 "SerialNumber": serialNumber,
Onur Kalinagac9f9faca2021-01-21 14:04:34 +0000160 "GroupAddress": groupAddress,
Matteo Scandolo446fc9e2020-03-13 15:48:13 -0700161 "err": err,
162 }).Errorf("Fail to send IGMP PktInd indication")
Anand S Katti09541352020-01-29 15:54:01 +0530163 return err
164 }
165 return nil
Arjun E Kdd443f02020-02-07 15:24:01 +0000166}
167
Matteo Scandolo618a6582020-09-09 12:21:29 -0700168func HandleNextPacket(ponPortId uint32, onuId uint32, serialNumber string, portNo uint32,
169 gemPortId uint32, macAddress net.HardwareAddr, pkt gopacket.Packet, cTag int, pbit uint8, stream bbsim.Stream) error {
170
171 igmpLayer := pkt.Layer(layers.LayerTypeIGMP)
172 if igmpLayer == nil {
173 log.WithFields(log.Fields{
174 "OnuId": onuId,
175 "SerialNumber": serialNumber,
176 "PortNo": portNo,
177 "Pkt": hex.EncodeToString(pkt.Data()),
178 }).Error("This is not an IGMP packet")
179 return errors.New("packet-is-not-igmp")
180 }
181
182 log.WithFields(log.Fields{
183 "Pkt": pkt.Data(),
184 }).Trace("IGMP packet")
185
186 igmp := igmpLayer.(*layers.IGMPv1or2)
187
188 if igmp.Type == layers.IGMPMembershipQuery {
Onur Kalinagac9f9faca2021-01-21 14:04:34 +0000189 _ = SendIGMPMembershipReportV2(ponPortId, onuId, serialNumber, portNo, gemPortId, macAddress,
190 cTag, pbit, stream, igmp.GroupAddress.String())
Matteo Scandolo618a6582020-09-09 12:21:29 -0700191 }
192
193 return nil
194}
195
Onur Kalinagac9f9faca2021-01-21 14:04:34 +0000196func createIGMPV3MembershipReportPacket(groupAddress string) *IGMP {
Arjun E Kdd443f02020-02-07 15:24:01 +0000197
Anand S Katti09541352020-01-29 15:54:01 +0530198 groupRecord1 := IGMPv3GroupRecord{
199 Type: IGMPv3GroupRecordType(IGMPIsIn),
200 AuxDataLen: 0, // this should always be 0 as per IGMPv3 spec.
201 NumberOfSources: 3,
202 MulticastAddress: net.IPv4(224, 0, 0, 22),
203 SourceAddresses: []net.IP{net.IPv4(15, 14, 20, 24), net.IPv4(15, 14, 20, 26), net.IPv4(15, 14, 20, 25)},
204 AuxData: 0, // NOT USED
205 }
Arjun E Kdd443f02020-02-07 15:24:01 +0000206
Anand S Katti09541352020-01-29 15:54:01 +0530207 groupRecord2 := IGMPv3GroupRecord{
208 Type: IGMPv3GroupRecordType(IGMPIsIn),
209 AuxDataLen: 0, // this should always be 0 as per IGMPv3 spec.
210 NumberOfSources: 2,
211 MulticastAddress: net.IPv4(224, 0, 0, 25),
212 SourceAddresses: []net.IP{net.IPv4(15, 14, 20, 30), net.IPv4(15, 14, 20, 31)},
213 AuxData: 0, // NOT USED
214 }
Arjun E Kdd443f02020-02-07 15:24:01 +0000215
Matteo Scandolo618a6582020-09-09 12:21:29 -0700216 igmpDefault := &IGMP{
217 Type: layers.IGMPMembershipReportV3, //IGMPV3 Membership Report
Anand S Katti09541352020-01-29 15:54:01 +0530218 MaxResponseTime: time.Duration(1),
219 Checksum: 0,
Onur Kalinagac9f9faca2021-01-21 14:04:34 +0000220 GroupAddress: net.ParseIP(groupAddress),
Anand S Katti09541352020-01-29 15:54:01 +0530221 SupressRouterProcessing: false,
222 RobustnessValue: 0,
223 IntervalTime: time.Duration(1),
224 SourceAddresses: []net.IP{net.IPv4(224, 0, 0, 24)},
225 NumberOfGroupRecords: 2,
226 NumberOfSources: 1,
227 GroupRecords: []IGMPv3GroupRecord{groupRecord1, groupRecord2},
228 Version: 3,
229 }
Arjun E Kdd443f02020-02-07 15:24:01 +0000230
Anand S Katti09541352020-01-29 15:54:01 +0530231 return igmpDefault
Arjun E Kdd443f02020-02-07 15:24:01 +0000232}
233
Onur Kalinagac9f9faca2021-01-21 14:04:34 +0000234func createIGMPV2MembershipReportPacket(groupAddress string) *IGMP {
Matteo Scandolo618a6582020-09-09 12:21:29 -0700235 return &IGMP{
236 Type: layers.IGMPMembershipReportV2, //IGMPV2 Membership Report
237 Checksum: 0,
Onur Kalinagac9f9faca2021-01-21 14:04:34 +0000238 GroupAddress: net.ParseIP(groupAddress),
Matteo Scandolo618a6582020-09-09 12:21:29 -0700239 Version: 2,
240 }
241}
242
Onur Kalinagac9f9faca2021-01-21 14:04:34 +0000243func createIGMPV2LeaveRequestPacket(groupAddress string) *IGMP {
Matteo Scandolo618a6582020-09-09 12:21:29 -0700244 return &IGMP{
245 Type: layers.IGMPLeaveGroup, //IGMPV2 Leave Group
Arjun E K57a7fcb2020-01-30 06:44:45 +0000246 MaxResponseTime: time.Duration(1),
247 Checksum: 0,
Onur Kalinagac9f9faca2021-01-21 14:04:34 +0000248 GroupAddress: net.ParseIP(groupAddress),
Arjun E K57a7fcb2020-01-30 06:44:45 +0000249 Version: 2,
250 }
251}
252
Matteo Scandolo618a6582020-09-09 12:21:29 -0700253func serializeIgmpPacket(intfId uint32, onuId uint32, cTag int, srcMac net.HardwareAddr, pbit uint8, igmp *IGMP) ([]byte, error) {
Arjun E K57a7fcb2020-01-30 06:44:45 +0000254 buffer := gopacket.NewSerializeBuffer()
255 options := gopacket.SerializeOptions{
256 ComputeChecksums: true,
257 FixLengths: true,
258 }
259
260 ethernetLayer := &layers.Ethernet{
261 SrcMAC: srcMac,
262 DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
263 EthernetType: layers.EthernetTypeIPv4,
264 }
265
266 ipLayer := &layers.IPv4{
267 Version: 4,
268 TOS: 0x10,
269 Id: 0,
270 TTL: 128,
271 SrcIP: []byte{0, 0, 0, 0},
Onur Kalinagac9f9faca2021-01-21 14:04:34 +0000272 DstIP: igmp.GroupAddress,
Arjun E K57a7fcb2020-01-30 06:44:45 +0000273 Protocol: layers.IPProtocolIGMP,
274 Options: []layers.IPv4Option{{OptionType: 148, OptionLength: 4, OptionData: make([]byte, 0)}}, //Adding router alert option
275 }
276
277 if err := gopacket.SerializeLayers(buffer, options, ethernetLayer, ipLayer, igmp); err != nil {
278 return nil, err
279 }
280
Matteo Scandolo618a6582020-09-09 12:21:29 -0700281 untaggedPkt := gopacket.NewPacket(buffer.Bytes(), layers.LayerTypeEthernet, gopacket.Default)
282 taggedPkt, err := packetHandlers.PushSingleTag(cTag, untaggedPkt, pbit)
283
284 if err != nil {
285 log.Error("TagPacket")
286 return nil, err
287 }
288
289 return taggedPkt.Data(), nil
Arjun E K57a7fcb2020-01-30 06:44:45 +0000290}
291
292//-----------------------------------------***********************---------------------------------
Arjun E K57a7fcb2020-01-30 06:44:45 +0000293
294type IGMP struct {
Matteo Scandolo618a6582020-09-09 12:21:29 -0700295 layers.BaseLayer
296 Type layers.IGMPType
Arjun E K57a7fcb2020-01-30 06:44:45 +0000297 MaxResponseTime time.Duration
298 Checksum uint16
299 GroupAddress net.IP
300 SupressRouterProcessing bool
301 RobustnessValue uint8
302 IntervalTime time.Duration
303 SourceAddresses []net.IP
304 NumberOfGroupRecords uint16
305 NumberOfSources uint16
Anand S Katti09541352020-01-29 15:54:01 +0530306 GroupRecords []IGMPv3GroupRecord
Arjun E K57a7fcb2020-01-30 06:44:45 +0000307 Version uint8 // IGMP protocol version
308}
309
Arjun E Kdd443f02020-02-07 15:24:01 +0000310// IGMPv3GroupRecord stores individual group records for a V3 Membership Report message.
311type IGMPv3GroupRecord struct {
Anand S Katti09541352020-01-29 15:54:01 +0530312 Type IGMPv3GroupRecordType
313 AuxDataLen uint8 // this should always be 0 as per IGMPv3 spec.
314 NumberOfSources uint16
315 MulticastAddress net.IP
316 SourceAddresses []net.IP
317 AuxData uint32 // NOT USED
Arjun E Kdd443f02020-02-07 15:24:01 +0000318}
319
320type IGMPv3GroupRecordType uint8
321
322const (
Anand S Katti09541352020-01-29 15:54:01 +0530323 IGMPIsIn IGMPv3GroupRecordType = 0x01 // Type MODE_IS_INCLUDE, source addresses x
324 IGMPIsEx IGMPv3GroupRecordType = 0x02 // Type MODE_IS_EXCLUDE, source addresses x
325 IGMPToIn IGMPv3GroupRecordType = 0x03 // Type CHANGE_TO_INCLUDE_MODE, source addresses x
326 IGMPToEx IGMPv3GroupRecordType = 0x04 // Type CHANGE_TO_EXCLUDE_MODE, source addresses x
327 IGMPAllow IGMPv3GroupRecordType = 0x05 // Type ALLOW_NEW_SOURCES, source addresses x
328 IGMPBlock IGMPv3GroupRecordType = 0x06 // Type BLOCK_OLD_SOURCES, source addresses x
Arjun E Kdd443f02020-02-07 15:24:01 +0000329)
330
331func (i IGMPv3GroupRecordType) String() string {
Anand S Katti09541352020-01-29 15:54:01 +0530332 switch i {
333 case IGMPIsIn:
334 return "MODE_IS_INCLUDE"
335 case IGMPIsEx:
336 return "MODE_IS_EXCLUDE"
337 case IGMPToIn:
338 return "CHANGE_TO_INCLUDE_MODE"
339 case IGMPToEx:
340 return "CHANGE_TO_EXCLUDE_MODE"
341 case IGMPAllow:
342 return "ALLOW_NEW_SOURCES"
343 case IGMPBlock:
344 return "BLOCK_OLD_SOURCES"
345 default:
346 return ""
347 }
Arjun E Kdd443f02020-02-07 15:24:01 +0000348}
349
Arjun E K57a7fcb2020-01-30 06:44:45 +0000350// SerializeTo writes the serialized form of this layer into the
351// SerializationBuffer, implementing gopacket.SerializableLayer.
352// See the docs for gopacket.SerializableLayer for more info.
Matteo Scandolo618a6582020-09-09 12:21:29 -0700353func (igmp *IGMP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
Arjun E K57a7fcb2020-01-30 06:44:45 +0000354 data, err := b.PrependBytes(8915)
Anand S Katti09541352020-01-29 15:54:01 +0530355 if err != nil {
356 return err
357 }
358 if igmp.Version == 2 {
359 data[0] = byte(igmp.Type)
360 data[1] = byte(igmp.MaxResponseTime)
361 data[2] = 0
362 data[3] = 0
363 copy(data[4:8], igmp.GroupAddress.To4())
364 if opts.ComputeChecksums {
365 igmp.Checksum = tcpipChecksum(data, 0)
366 binary.BigEndian.PutUint16(data[2:4], igmp.Checksum)
367 }
368 } else if igmp.Version == 3 {
Arjun E K57a7fcb2020-01-30 06:44:45 +0000369
Anand S Katti09541352020-01-29 15:54:01 +0530370 data[0] = byte(igmp.Type)
371 data[1] = 0
372 data[2] = 0
373 data[3] = 0
374 data[4] = 0
375 data[5] = 0
376 binary.BigEndian.PutUint16(data[6:8], igmp.NumberOfGroupRecords)
377 j := 8
378 for i := uint16(0); i < igmp.NumberOfGroupRecords; i++ {
379 data[j] = byte(igmp.GroupRecords[i].Type)
380 data[j+1] = byte(0)
381 binary.BigEndian.PutUint16(data[j+2:j+4], igmp.GroupRecords[i].NumberOfSources)
382 copy(data[j+4:j+8], igmp.GroupRecords[i].MulticastAddress.To4())
383 j = j + 8
384 for m := uint16(0); m < igmp.GroupRecords[i].NumberOfSources; m++ {
385 copy(data[j:(j+4)], igmp.GroupRecords[i].SourceAddresses[m].To4())
386 j = j + 4
387 }
388 }
389 if opts.ComputeChecksums {
390 igmp.Checksum = tcpipChecksum(data, 0)
391 binary.BigEndian.PutUint16(data[2:4], igmp.Checksum)
392 }
393 }
394 return nil
Arjun E K57a7fcb2020-01-30 06:44:45 +0000395}
396
397// Calculate the TCP/IP checksum defined in rfc1071. The passed-in csum is any
398// initial checksum data that's already been computed.
399func tcpipChecksum(data []byte, csum uint32) uint16 {
400 // to handle odd lengths, we loop to length - 1, incrementing by 2, then
401 // handle the last byte specifically by checking against the original
402 // length.
403 length := len(data) - 1
404 for i := 0; i < length; i += 2 {
405 // For our test packet, doing this manually is about 25% faster
406 // (740 ns vs. 1000ns) than doing it by calling binary.BigEndian.Uint16.
407 csum += uint32(data[i]) << 8
408 csum += uint32(data[i+1])
409 }
410 if len(data)%2 == 1 {
411 csum += uint32(data[length]) << 8
412 }
413 for csum > 0xffff {
414 csum = (csum >> 16) + (csum & 0xffff)
415 }
416 return ^uint16(csum)
417}
418
Matteo Scandolo618a6582020-09-09 12:21:29 -0700419func (i *IGMP) LayerType() gopacket.LayerType { return layers.LayerTypeIGMP }
420func (i *IGMP) LayerContents() []byte { return i.Contents }
421func (i *IGMP) LayerPayload() []byte { return i.Payload }