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