blob: cfdb07956117db9ddcf15b52cd0bffb450a86e11 [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"
18 "github.com/google/gopacket"
19 "github.com/google/gopacket/layers"
20 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
21 omci "github.com/opencord/omci-sim"
22 "github.com/opencord/voltha-protos/v2/go/openolt"
23 log "github.com/sirupsen/logrus"
24 "net"
25 "time"
26)
27
28func SendIGMPLeaveGroupV2(ponPortId uint32, onuId uint32, serialNumber string, portNo uint32, macAddress net.HardwareAddr, stream bbsim.Stream) error {
29 log.WithFields(log.Fields{
30 "OnuId": onuId,
31 "SerialNumber": serialNumber,
32 "PortNo": portNo,
33 }).Debugf("Entered SendIGMPLeaveGroupV2")
34 igmp := createIGMPV2LeaveRequestPacket()
35 pkt, err := serializeIgmpPacket(ponPortId, onuId, macAddress, igmp)
36
37 if err != nil {
38 log.WithFields(log.Fields{
39 "OnuId": onuId,
40 "IntfId": ponPortId,
41 "SerialNumber": serialNumber,
42 }).Errorf("Seriliazation of igmp packet failed : %s", err)
43 return err
44 }
45
46 gemid, err := omci.GetGemPortId(ponPortId, onuId)
47 if err != nil {
48 log.WithFields(log.Fields{
49 "OnuId": onuId,
50 "IntfId": ponPortId,
51 "SerialNumber": serialNumber,
52 }).Errorf("Can't retrieve GemPortId for IGMP: %s", err)
53 return err
54 }
55
56 data := &openolt.Indication_PktInd{
57 PktInd: &openolt.PacketIndication{
58 IntfType: "pon",
59 IntfId: ponPortId,
60 GemportId: uint32(gemid),
61 Pkt: pkt,
62 PortNo: portNo,
63 },
64 }
65 //Sending IGMP packets
66 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
67 log.Errorf("Fail to send IGMP PktInd indication for ONU: %s, IntfId: %s, SerialNumber: %s, error: %v", onuId, ponPortId, serialNumber, err)
68 return err
69 }
70 return nil
71}
72
73func SendIGMPMembershipReportV2(ponPortId uint32, onuId uint32, serialNumber string, portNo uint32, macAddress net.HardwareAddr, stream bbsim.Stream) error {
74 log.WithFields(log.Fields{
75 "OnuId": onuId,
76 "SerialNumber": serialNumber,
77 "PortNo": portNo,
78 }).Debugf("Entered SendIGMPMembershipReportV2")
79 igmp := createIGMPV2MembershipReportPacket()
80 pkt, err := serializeIgmpPacket(ponPortId, onuId, macAddress, igmp)
81
82 if err != nil {
83 log.WithFields(log.Fields{
84 "OnuId": onuId,
85 "IntfId": ponPortId,
86 "SerialNumber": serialNumber,
87 }).Errorf("Seriliazation of igmp packet failed : %s", err)
88 return err
89 }
90
91 gemid, err := omci.GetGemPortId(ponPortId, onuId)
92 if err != nil {
93 log.WithFields(log.Fields{
94 "OnuId": onuId,
95 "IntfId": ponPortId,
96 "SerialNumber": serialNumber,
97 }).Errorf("Can't retrieve GemPortId for IGMP: %s", err)
98 return err
99 }
100
101 data := &openolt.Indication_PktInd{
102 PktInd: &openolt.PacketIndication{
103 IntfType: "pon",
104 IntfId: ponPortId,
105 GemportId: uint32(gemid),
106 Pkt: pkt,
107 PortNo: portNo,
108 },
109 }
110 //Sending IGMP packets
111 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
112 log.Errorf("Fail to send IGMP PktInd indication for ONU: %s, IntfId: %s, SerialNumber: %s, error: %v", onuId, ponPortId, serialNumber, err)
113 return err
114 }
115 return nil
116}
117
118//func serializeIgmpPacket(intfId uint32, onuId uint32, srcMac net.HardwareAddr, igmp *layers.IGMP) ([]byte, error) {
119func createIGMPV2MembershipReportPacket() IGMP {
120 return IGMP{
121 Type: 0x16, //IGMPV2 Membership Report
122 MaxResponseTime: time.Duration(1),
123 Checksum: 0,
124 GroupAddress: net.IPv4(224, 0, 0, 22),
125 Version: 2,
126 }
127}
128
129func createIGMPV2LeaveRequestPacket() IGMP {
130 return IGMP{
131 Type: 0x17, //IGMPV2 Leave Group
132 MaxResponseTime: time.Duration(1),
133 Checksum: 0,
134 GroupAddress: net.IPv4(224, 0, 0, 22),
135 Version: 2,
136 }
137}
138
139func serializeIgmpPacket(intfId uint32, onuId uint32, srcMac net.HardwareAddr, igmp IGMP) ([]byte, error) {
140 buffer := gopacket.NewSerializeBuffer()
141 options := gopacket.SerializeOptions{
142 ComputeChecksums: true,
143 FixLengths: true,
144 }
145
146 ethernetLayer := &layers.Ethernet{
147 SrcMAC: srcMac,
148 DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
149 EthernetType: layers.EthernetTypeIPv4,
150 }
151
152 ipLayer := &layers.IPv4{
153 Version: 4,
154 TOS: 0x10,
155 Id: 0,
156 TTL: 128,
157 SrcIP: []byte{0, 0, 0, 0},
158 DstIP: []byte{224, 0, 0, 22},
159 Protocol: layers.IPProtocolIGMP,
160 Options: []layers.IPv4Option{{OptionType: 148, OptionLength: 4, OptionData: make([]byte, 0)}}, //Adding router alert option
161 }
162
163 if err := gopacket.SerializeLayers(buffer, options, ethernetLayer, ipLayer, igmp); err != nil {
164 return nil, err
165 }
166
167 return buffer.Bytes(), nil
168}
169
170//-----------------------------------------***********************---------------------------------
171// BaseLayer is a convenience struct which implements the LayerData and
172// LayerPayload functions of the Layer interface.
173type BaseLayer struct {
174 // Contents is the set of bytes that make up this layer. IE: for an
175 // Ethernet packet, this would be the set of bytes making up the
176 // Ethernet frame.
177 Contents []byte
178 // Payload is the set of bytes contained by (but not part of) this
179 // Layer. Again, to take Ethernet as an example, this would be the
180 // set of bytes encapsulated by the Ethernet protocol.
181 Payload []byte
182}
183
184type IGMPType uint8
185
186type IGMP struct {
187 BaseLayer
188 Type IGMPType
189 MaxResponseTime time.Duration
190 Checksum uint16
191 GroupAddress net.IP
192 SupressRouterProcessing bool
193 RobustnessValue uint8
194 IntervalTime time.Duration
195 SourceAddresses []net.IP
196 NumberOfGroupRecords uint16
197 NumberOfSources uint16
198 Version uint8 // IGMP protocol version
199}
200
201// SerializeTo writes the serialized form of this layer into the
202// SerializationBuffer, implementing gopacket.SerializableLayer.
203// See the docs for gopacket.SerializableLayer for more info.
204// SerializeTo writes the serialized form of this layer into the
205// SerializationBuffer, implementing gopacket.SerializableLayer.
206// See the docs for gopacket.SerializableLayer for more info.
207func (igmp IGMP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
208 // func (igmp *IGMP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
209 log.Debugf("Serializing IGMP Packet")
210 //TODO - add length check here
211 data, err := b.PrependBytes(8915)
212 if err != nil {
213 return err
214 }
215
216 data[0] = byte(igmp.Type)
217 data[1] = byte(igmp.MaxResponseTime)
218 data[2] = 0
219 data[3] = 0
220 copy(data[4:8], igmp.GroupAddress.To4())
221 if opts.ComputeChecksums {
222 igmp.Checksum = tcpipChecksum(data, 0)
223 binary.BigEndian.PutUint16(data[2:4], igmp.Checksum)
224 }
225 return nil
226}
227
228// Calculate the TCP/IP checksum defined in rfc1071. The passed-in csum is any
229// initial checksum data that's already been computed.
230func tcpipChecksum(data []byte, csum uint32) uint16 {
231 // to handle odd lengths, we loop to length - 1, incrementing by 2, then
232 // handle the last byte specifically by checking against the original
233 // length.
234 length := len(data) - 1
235 for i := 0; i < length; i += 2 {
236 // For our test packet, doing this manually is about 25% faster
237 // (740 ns vs. 1000ns) than doing it by calling binary.BigEndian.Uint16.
238 csum += uint32(data[i]) << 8
239 csum += uint32(data[i+1])
240 }
241 if len(data)%2 == 1 {
242 csum += uint32(data[length]) << 8
243 }
244 for csum > 0xffff {
245 csum = (csum >> 16) + (csum & 0xffff)
246 }
247 return ^uint16(csum)
248}
249
250func (IGMP) LayerType() gopacket.LayerType { return layers.LayerTypeIGMP }