blob: 75e1d7baebba8908451867783268a22a3564c771 [file] [log] [blame]
David K. Bainbridged77028f2017-08-01 12:47:55 -07001/*
Brian O'Connor4d084702017-08-03 22:45:58 -07002 * Copyright 2017-present Open Networking Foundation
David K. Bainbridged77028f2017-08-01 12:47:55 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
ke han81a38b92017-03-10 18:41:44 +080016package org.opencord.igmpproxy;
17
18import org.onlab.packet.Ethernet;
19import org.onlab.packet.IGMP;
20import org.onlab.packet.IGMPMembership;
21import org.onlab.packet.IGMPQuery;
22import org.onlab.packet.IPv4;
23import org.onlab.packet.Ip4Address;
24import org.onlab.packet.MacAddress;
25import org.onosproject.mastership.MastershipService;
26import org.onosproject.net.DeviceId;
27import org.onosproject.net.PortNumber;
28import org.onosproject.net.flow.DefaultTrafficTreatment;
29import org.onosproject.net.flow.TrafficTreatment;
30import org.onosproject.net.packet.DefaultOutboundPacket;
31import org.onosproject.net.packet.OutboundPacket;
32import org.onosproject.net.packet.PacketService;
33
34import java.nio.ByteBuffer;
35
36/**
37 * Message encode and send interface for igmpproxy.
38 */
39public final class IgmpSender {
40 static final String V3_REPORT_ADDRESS = "224.0.0.22";
41 static final String MAC_ADDRESS = "DE:AD:BE:EF:BA:11";
42 static final short DEFAULT_MVLAN = 4000;
43 static final byte DEFAULT_COS = 7;
44 static final int DEFAULT_MEX_RESP = 10;
45 static final byte[] RA_BYTES = {(byte) 0x94, (byte) 0x04, (byte) 0x00, (byte) 0x00};
46
47 private static IgmpSender instance = null;
48 private PacketService packetService;
49 private MastershipService mastershipService;
50 private boolean withRAUplink = true;
51 private boolean withRADownlink = false;
52 private short mvlan = DEFAULT_MVLAN;
53 private byte igmpCos = DEFAULT_COS;
54 private int maxResp = DEFAULT_MEX_RESP;
55
56 private IgmpSender(PacketService packetService, MastershipService mastershipService) {
57 this.packetService = packetService;
58 this.mastershipService = mastershipService;
59 }
60
61 public static void init(PacketService packetService, MastershipService mastershipService) {
62 instance = new IgmpSender(packetService, mastershipService);
63 }
64
65 public static IgmpSender getInstance() {
66 return instance;
67 }
68
69 public void setWithRAUplink(boolean withRaUplink) {
70 this.withRAUplink = withRaUplink;
71 }
72
73 public void setWithRADownlink(boolean withRADownlink) {
74 this.withRADownlink = withRADownlink;
75 }
76
77 public void setMvlan(short mvlan) {
78 this.mvlan = mvlan;
79 }
80
81 public void setIgmpCos(byte igmpCos) {
82 this.igmpCos = igmpCos;
83 }
84
85 public void setMaxResp(int maxResp) {
86 this.maxResp = maxResp;
87 }
88
89 public Ethernet buildIgmpV3Join(Ip4Address groupIp, Ip4Address sourceIp) {
90 IGMPMembership igmpMembership = new IGMPMembership(groupIp);
91 igmpMembership.setRecordType(IGMPMembership.CHANGE_TO_EXCLUDE_MODE);
92
93 return buildIgmpPacket(IGMP.TYPE_IGMPV3_MEMBERSHIP_REPORT, groupIp, igmpMembership, sourceIp, false);
94 }
95
96 public Ethernet buildIgmpV3ResponseQuery(Ip4Address groupIp, Ip4Address sourceIp) {
97 IGMPMembership igmpMembership = new IGMPMembership(groupIp);
98 igmpMembership.setRecordType(IGMPMembership.MODE_IS_EXCLUDE);
99
100 return buildIgmpPacket(IGMP.TYPE_IGMPV3_MEMBERSHIP_REPORT, groupIp, igmpMembership, sourceIp, false);
101 }
102
103 public Ethernet buildIgmpV3Leave(Ip4Address groupIp, Ip4Address sourceIp) {
104 IGMPMembership igmpMembership = new IGMPMembership(groupIp);
105 igmpMembership.setRecordType(IGMPMembership.CHANGE_TO_INCLUDE_MODE);
106
107 return buildIgmpPacket(IGMP.TYPE_IGMPV3_MEMBERSHIP_REPORT, groupIp, igmpMembership, sourceIp, false);
108 }
109
110 public Ethernet buildIgmpV2Query(Ip4Address groupIp, Ip4Address sourceIp) {
111 return buildIgmpPacket(IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY, groupIp, null, sourceIp, true);
112 }
113
114 public Ethernet buildIgmpV3Query(Ip4Address groupIp, Ip4Address sourceIp) {
115 return buildIgmpPacket(IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY, groupIp, null, sourceIp, false);
116 }
117
118 private Ethernet buildIgmpPacket(byte type, Ip4Address groupIp, IGMPMembership igmpMembership,
119 Ip4Address sourceIp, boolean isV2Query) {
120
121 IGMP igmpPacket;
122 if (isV2Query) {
123 igmpPacket = new IGMP.IGMPv2();
124 } else {
125 igmpPacket = new IGMP.IGMPv3();
126 }
127
128 IPv4 ip4Packet = new IPv4();
129 Ethernet ethPkt = new Ethernet();
130
131 igmpPacket.setIgmpType(type);
132
133 switch (type) {
134 case IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY:
135 igmpPacket.setMaxRespCode((byte) (maxResp * 10));
136 IGMPQuery igmpQuery = new IGMPQuery(groupIp, 0);
137
138 igmpPacket.addGroup(igmpQuery);
139 ip4Packet.setDestinationAddress(groupIp.toInt());
140 if (withRADownlink) {
141 ip4Packet.setOptions(RA_BYTES);
142 }
143 break;
144
145 case IGMP.TYPE_IGMPV3_MEMBERSHIP_REPORT:
146 if (igmpMembership == null) {
147 return null;
148 }
149 igmpPacket.addGroup(igmpMembership);
150 if (type == IGMP.TYPE_IGMPV3_MEMBERSHIP_REPORT) {
151 ip4Packet.setDestinationAddress(Ip4Address.valueOf(V3_REPORT_ADDRESS).toInt());
152 } else {
153 ip4Packet.setDestinationAddress(groupIp.toInt());
154 }
155 if (withRAUplink) {
156 ip4Packet.setOptions(RA_BYTES);
157 }
158 break;
159
160 case IGMP.TYPE_IGMPV2_MEMBERSHIP_REPORT:
161 case IGMP.TYPE_IGMPV2_LEAVE_GROUP:
162 return null;
163 default:
164 return null;
165 }
166
167 igmpPacket.setParent(ip4Packet);
168 ip4Packet.setSourceAddress(sourceIp.toInt());
169 ip4Packet.setProtocol(IPv4.PROTOCOL_IGMP);
170 ip4Packet.setPayload(igmpPacket);
171 ip4Packet.setParent(ethPkt);
172 ip4Packet.setTtl((byte) 0x78);
173
174 ethPkt.setDestinationMACAddress(multiaddToMac(ip4Packet.getDestinationAddress()));
175 ethPkt.setSourceMACAddress(MAC_ADDRESS);
176 ethPkt.setEtherType(Ethernet.TYPE_IPV4);
177 ethPkt.setPayload(ip4Packet);
178 ethPkt.setVlanID(mvlan);
179 ethPkt.setPriorityCode(igmpCos);
180
181 return ethPkt;
182 }
183
184 private MacAddress multiaddToMac(int multiaddress) {
185 byte[] b = new byte[3];
186 b[0] = (byte) (multiaddress & 0xff);
187 b[1] = (byte) (multiaddress >> 8 & 0xff);
188 b[2] = (byte) (multiaddress >> 16 & 0x7f);
189 byte[] macByte = {0x01, 0x00, 0x5e, b[2], b[1], b[0]};
190
191 MacAddress mac = MacAddress.valueOf(macByte);
192 return mac;
193 }
194
195 public void sendIgmpPacketUplink(Ethernet ethPkt, DeviceId deviceId) {
196 if (!mastershipService.isLocalMaster(deviceId)) {
197 return;
198 }
199
200
201 if (IgmpManager.connectPointMode) {
202 sendIgmpPacket(ethPkt, IgmpManager.connectPoint.deviceId(), IgmpManager.connectPoint.port());
203 } else {
204 PortNumber upLink = IgmpManager.getDeviceUplink(deviceId);
205 sendIgmpPacket(ethPkt, deviceId, upLink);
206 }
207 }
208
209 public void sendIgmpPacket(Ethernet ethPkt, DeviceId deviceId, PortNumber portNumber) {
210 if (!mastershipService.isLocalMaster(deviceId)) {
211 return;
212 }
213
214 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
215 .setOutput(portNumber).build();
216 OutboundPacket packet = new DefaultOutboundPacket(deviceId,
217 treatment, ByteBuffer.wrap(ethPkt.serialize()));
218 packetService.emit(packet);
219
220 }
221}