2 * Copyright (c) 2016 Dell Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.netvirt.ipv6service;
11 import java.nio.ByteBuffer;
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.List;
15 import org.opendaylight.netvirt.ipv6service.utils.Ipv6Constants;
16 import org.opendaylight.netvirt.ipv6service.utils.Ipv6Constants.Ipv6RtrAdvertType;
17 import org.opendaylight.netvirt.ipv6service.utils.Ipv6ServiceUtils;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.EthernetHeader;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.Ipv6Header;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.RouterAdvertisementPacket;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.RouterAdvertisementPacketBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.RouterSolicitationPacket;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.router.advertisement.packet.PrefixList;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.router.advertisement.packet.PrefixListBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
35 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
39 public class Ipv6RouterAdvt {
40 private static final Logger LOG = LoggerFactory.getLogger(Ipv6RouterAdvt.class);
41 private static PacketProcessingService pktService;
42 private Ipv6ServiceUtils ipv6Utils;
44 public Ipv6RouterAdvt() {
45 ipv6Utils = Ipv6ServiceUtils.getInstance();
48 public static void setPacketProcessingService(PacketProcessingService packetService) {
49 pktService = packetService;
52 public boolean transmitRtrAdvertisement(Ipv6RtrAdvertType raType, VirtualPort routerPort,
53 List<NodeConnectorRef> outportList, RouterSolicitationPacket rsPdu) {
54 if (pktService == null) {
55 LOG.info("transmitRtrAdvertisement packet processing service is not yet configured");
58 RouterAdvertisementPacketBuilder raPacket = new RouterAdvertisementPacketBuilder();
59 updateRAResponse(raType, rsPdu, raPacket, routerPort);
60 // Serialize the response packet
61 byte[] txPayload = fillRouterAdvertisementPacket(raPacket.build());
62 for (NodeConnectorRef outport: outportList) {
63 InstanceIdentifier<Node> outNode = outport.getValue().firstIdentifierOf(Node.class);
64 TransmitPacketInput input = new TransmitPacketInputBuilder().setPayload(txPayload)
65 .setNode(new NodeRef(outNode))
66 .setEgress(outport).build();
67 LOG.debug("Transmitting the Router Advt packet out {}", outport);
68 pktService.transmitPacket(input);
73 private void updateRAResponse(Ipv6RtrAdvertType raType, RouterSolicitationPacket pdu,
74 RouterAdvertisementPacketBuilder raPacket,
75 VirtualPort routerPort) {
76 short icmpv6RaFlags = 0;
77 String gatewayMac = null;
79 List<String> autoConfigPrefixList = new ArrayList<String>();
80 List<String> statefulConfigPrefixList = new ArrayList<String>();
82 for (VirtualSubnet subnet : routerPort.getSubnets()) {
83 gatewayIp = subnet.getGatewayIp();
84 // Skip if its a v4 subnet.
85 if (gatewayIp.getIpv4Address() != null) {
89 if (!subnet.getIpv6RAMode().isEmpty()) {
90 if (Ipv6Constants.IPV6_AUTO_ADDRESS_SUBNETS.contains(subnet.getIpv6RAMode())) {
91 autoConfigPrefixList.add(String.valueOf(subnet.getSubnetCidr().getValue()));
94 if (subnet.getIpv6RAMode().equalsIgnoreCase(Ipv6Constants.IPV6_DHCPV6_STATEFUL)) {
95 statefulConfigPrefixList.add(String.valueOf(subnet.getSubnetCidr().getValue()));
99 if (subnet.getIpv6RAMode().equalsIgnoreCase(Ipv6Constants.IPV6_DHCPV6_STATELESS)) {
100 icmpv6RaFlags = (short) (icmpv6RaFlags | (1 << 6)); // Other Configuration.
101 } else if (subnet.getIpv6RAMode().equalsIgnoreCase(Ipv6Constants.IPV6_DHCPV6_STATEFUL)) {
102 icmpv6RaFlags = (short) (icmpv6RaFlags | (1 << 7)); // Managed Address Conf.
106 gatewayMac = routerPort.getMacAddress();
108 MacAddress sourceMac = MacAddress.getDefaultInstance(gatewayMac);
109 raPacket.setSourceMac(sourceMac);
110 if (raType == Ipv6RtrAdvertType.SOLICITED_ADVERTISEMENT) {
111 raPacket.setDestinationMac(pdu.getSourceMac());
112 raPacket.setDestinationIpv6(pdu.getSourceIpv6());
113 raPacket.setFlowLabel(pdu.getFlowLabel());
115 raPacket.setDestinationMac(new MacAddress(Ipv6Constants.DEF_MCAST_MAC));
116 raPacket.setDestinationIpv6(Ipv6ServiceUtils.ALL_NODES_MCAST_ADDR);
117 raPacket.setFlowLabel(Ipv6Constants.DEF_FLOWLABEL);
120 raPacket.setEthertype(Ipv6Constants.IP_V6_ETHTYPE);
122 raPacket.setVersion(Ipv6Constants.IPV6_VERSION);
123 int prefixListLength = autoConfigPrefixList.size() + statefulConfigPrefixList.size();
124 raPacket.setIpv6Length(Ipv6Constants.ICMPV6_RA_LENGTH_WO_OPTIONS
125 + Ipv6Constants.ICMPV6_OPTION_SOURCE_LLA_LENGTH
126 + prefixListLength * Ipv6Constants.ICMPV6_OPTION_PREFIX_LENGTH);
127 raPacket.setNextHeader(Ipv6Constants.ICMP6_NHEADER);
128 raPacket.setHopLimit(Ipv6Constants.ICMP_V6_MAX_HOP_LIMIT);
129 raPacket.setSourceIpv6(ipv6Utils.getIpv6LinkLocalAddressFromMac(sourceMac));
131 raPacket.setIcmp6Type(Ipv6Constants.ICMP_V6_RA_CODE);
132 raPacket.setIcmp6Code((short)0);
133 raPacket.setIcmp6Chksum(0);
135 raPacket.setCurHopLimit((short) Ipv6Constants.IPV6_DEFAULT_HOP_LIMIT);
136 raPacket.setFlags((short) icmpv6RaFlags);
138 if (raType == Ipv6RtrAdvertType.CEASE_ADVERTISEMENT) {
139 raPacket.setRouterLifetime(0);
141 raPacket.setRouterLifetime(Ipv6Constants.IPV6_ROUTER_LIFETIME);
143 raPacket.setReachableTime((long) Ipv6Constants.IPV6_RA_REACHABLE_TIME);
144 raPacket.setRetransTime((long) 0);
146 raPacket.setOptionSourceAddr((short)1);
147 raPacket.setSourceAddrLength((short)1);
148 raPacket.setSourceLlAddress(MacAddress.getDefaultInstance(gatewayMac));
150 List<PrefixList> prefixList = new ArrayList<PrefixList>();
151 PrefixListBuilder prefix = new PrefixListBuilder();
152 prefix.setOptionType((short)3);
153 prefix.setOptionLength((short)4);
154 // Note: EUI-64 auto-configuration requires 64 bits.
155 prefix.setPrefixLength((short)64);
156 prefix.setValidLifetime((long) Ipv6Constants.IPV6_RA_VALID_LIFETIME);
157 prefix.setPreferredLifetime((long) Ipv6Constants.IPV6_RA_PREFERRED_LIFETIME);
158 prefix.setReserved((long) 0);
160 short autoConfPrefixFlags = 0;
161 autoConfPrefixFlags = (short) (autoConfPrefixFlags | (1 << 7)); // On-link flag
162 autoConfPrefixFlags = (short) (autoConfPrefixFlags | (1 << 6)); // Autonomous address-configuration flag.
163 for (String v6Prefix : autoConfigPrefixList) {
164 prefix.setFlags((short)autoConfPrefixFlags);
165 prefix.setPrefix(new Ipv6Prefix(v6Prefix));
166 prefixList.add(prefix.build());
169 short statefulPrefixFlags = 0;
170 statefulPrefixFlags = (short) (statefulPrefixFlags | (1 << 7)); // On-link flag
171 for (String v6Prefix : statefulConfigPrefixList) {
172 prefix.setFlags((short)statefulPrefixFlags);
173 prefix.setPrefix(new Ipv6Prefix(v6Prefix));
174 prefixList.add(prefix.build());
177 raPacket.setPrefixList((List<PrefixList>) prefixList);
182 private byte[] fillRouterAdvertisementPacket(RouterAdvertisementPacket pdu) {
183 ByteBuffer buf = ByteBuffer.allocate(Ipv6Constants.ICMPV6_OFFSET + pdu.getIpv6Length());
185 buf.put(ipv6Utils.convertEthernetHeaderToByte((EthernetHeader)pdu), 0, 14);
186 buf.put(ipv6Utils.convertIpv6HeaderToByte((Ipv6Header)pdu), 0, 40);
187 buf.put(icmp6RAPayloadtoByte(pdu), 0, pdu.getIpv6Length());
188 int checksum = ipv6Utils.calcIcmpv6Checksum(buf.array(), (Ipv6Header) pdu);
189 buf.putShort((Ipv6Constants.ICMPV6_OFFSET + 2), (short)checksum);
190 return (buf.array());
193 private byte[] icmp6RAPayloadtoByte(RouterAdvertisementPacket pdu) {
194 byte[] data = new byte[pdu.getIpv6Length()];
195 Arrays.fill(data, (byte)0);
197 ByteBuffer buf = ByteBuffer.wrap(data);
198 buf.put((byte)pdu.getIcmp6Type().shortValue());
199 buf.put((byte)pdu.getIcmp6Code().shortValue());
200 buf.putShort((short)pdu.getIcmp6Chksum().intValue());
201 buf.put((byte)pdu.getCurHopLimit().shortValue());
202 buf.put((byte)pdu.getFlags().shortValue());
203 buf.putShort((short)pdu.getRouterLifetime().intValue());
204 buf.putInt((int)pdu.getReachableTime().longValue());
205 buf.putInt((int)pdu.getRetransTime().longValue());
206 buf.put((byte)pdu.getOptionSourceAddr().shortValue());
207 buf.put((byte)pdu.getSourceAddrLength().shortValue());
208 buf.put(ipv6Utils.bytesFromHexString(pdu.getSourceLlAddress().getValue().toString()));
210 for (PrefixList prefix : pdu.getPrefixList()) {
211 buf.put((byte)prefix.getOptionType().shortValue());
212 buf.put((byte)prefix.getOptionLength().shortValue());
213 buf.put((byte)prefix.getPrefixLength().shortValue());
214 buf.put((byte)prefix.getFlags().shortValue());
215 buf.putInt((int)prefix.getValidLifetime().longValue());
216 buf.putInt((int)prefix.getPreferredLifetime().longValue());
217 buf.putInt((int)prefix.getReserved().longValue());
218 buf.put(IetfInetUtil.INSTANCE.ipv6PrefixToBytes(new Ipv6Prefix(prefix.getPrefix())),0,16);