2 * Copyright © 2016, 2017 Red Hat, 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.utils;
11 import java.net.InetAddress;
12 import java.net.UnknownHostException;
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.List;
16 import java.util.Optional;
17 import java.util.concurrent.ExecutionException;
18 import javax.inject.Inject;
19 import javax.inject.Singleton;
20 import org.apache.commons.lang3.StringUtils;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.opendaylight.genius.ipv6util.api.Icmpv6Type;
23 import org.opendaylight.genius.ipv6util.api.Ipv6Constants;
24 import org.opendaylight.genius.ipv6util.api.Ipv6Util;
25 import org.opendaylight.genius.mdsalutil.ActionInfo;
26 import org.opendaylight.genius.mdsalutil.FlowEntity;
27 import org.opendaylight.genius.mdsalutil.InstructionInfo;
28 import org.opendaylight.genius.mdsalutil.MDSALUtil;
29 import org.opendaylight.genius.mdsalutil.MatchInfo;
30 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
31 import org.opendaylight.genius.mdsalutil.NwConstants;
32 import org.opendaylight.genius.mdsalutil.NwConstants.NxmOfFieldType;
33 import org.opendaylight.genius.mdsalutil.actions.ActionLearn;
34 import org.opendaylight.genius.mdsalutil.actions.ActionLearn.FlowMod;
35 import org.opendaylight.genius.mdsalutil.actions.ActionMoveSourceDestinationEth;
36 import org.opendaylight.genius.mdsalutil.actions.ActionMoveSourceDestinationIpv6;
37 import org.opendaylight.genius.mdsalutil.actions.ActionNdOptionType;
38 import org.opendaylight.genius.mdsalutil.actions.ActionNdReserved;
39 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
40 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
41 import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
42 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource;
43 import org.opendaylight.genius.mdsalutil.actions.ActionSetIcmpv6Type;
44 import org.opendaylight.genius.mdsalutil.actions.ActionSetIpv6NdTarget;
45 import org.opendaylight.genius.mdsalutil.actions.ActionSetIpv6NdTll;
46 import org.opendaylight.genius.mdsalutil.actions.ActionSetSourceIpv6;
47 import org.opendaylight.genius.mdsalutil.ericmatches.MatchNdOptionType;
48 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
49 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
50 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
51 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
52 import org.opendaylight.genius.mdsalutil.matches.MatchIcmpv6;
53 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
54 import org.opendaylight.genius.mdsalutil.matches.MatchIpv6NdTarget;
55 import org.opendaylight.genius.mdsalutil.matches.MatchIpv6Source;
56 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
57 import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
58 import org.opendaylight.genius.utils.ServiceIndex;
59 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
60 import org.opendaylight.mdsal.binding.api.DataBroker;
61 import org.opendaylight.mdsal.binding.api.ReadTransaction;
62 import org.opendaylight.mdsal.binding.util.Datastore;
63 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
64 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
65 import org.opendaylight.mdsal.binding.util.TypedReadWriteTransaction;
66 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
67 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
68 import org.opendaylight.netvirt.ipv6service.VirtualSubnet;
69 import org.opendaylight.netvirt.ipv6service.api.IVirtualPort;
70 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
71 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
72 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
73 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
74 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
75 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
76 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.config.rev181010.Ipv6serviceConfig;
89 import org.opendaylight.yangtools.yang.binding.DataObject;
90 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
91 import org.opendaylight.yangtools.yang.common.Uint64;
92 import org.slf4j.Logger;
93 import org.slf4j.LoggerFactory;
96 public class Ipv6ServiceUtils {
97 private static final Logger LOG = LoggerFactory.getLogger(Ipv6ServiceUtils.class);
98 public static final Ipv6Address ALL_NODES_MCAST_ADDR = newIpv6Address(Ipv6Constants.ALL_NODES_MCAST_ADDRESS);
99 public static final Ipv6Address UNSPECIFIED_ADDR = newIpv6Address("0:0:0:0:0:0:0:0");
102 private static Ipv6Address newIpv6Address(String ip) {
104 return Ipv6Address.getDefaultInstance(InetAddress.getByName(ip).getHostAddress());
105 } catch (UnknownHostException e) {
106 LOG.error("Ipv6ServiceUtils: Error instantiating ipv6 address", e);
111 private final DataBroker broker;
112 private final IMdsalApiManager mdsalUtil;
113 private final IpV6NAConfigHelper ipV6NAConfigHelper;
114 private final ManagedNewTransactionRunner txRunner;
115 private final Ipv6serviceConfig ipv6serviceConfig;
118 public Ipv6ServiceUtils(DataBroker broker, IMdsalApiManager mdsalUtil,IpV6NAConfigHelper ipV6NAConfigHelper,
119 Ipv6serviceConfig ipv6ServiceConfig) {
120 this.broker = broker;
121 this.mdsalUtil = mdsalUtil;
122 this.ipV6NAConfigHelper = ipV6NAConfigHelper;
123 this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
124 this.ipv6serviceConfig = ipv6ServiceConfig;
128 * Retrieves the object from the datastore.
129 * @param datastoreType the data store type.
130 * @param path the wild card path.
131 * @return the required object.
133 public <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
134 try (ReadTransaction tx = broker.newReadOnlyTransaction()) {
135 return tx.read(datastoreType, path).get();
136 } catch (InterruptedException | ExecutionException e) {
137 throw new RuntimeException(e);
142 * Retrieves the Interface from the datastore.
143 * @param interfaceName the interface name
144 * @return the interface.
146 public org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
147 .@Nullable Interface getInterface(String interfaceName) {
148 return read(LogicalDatastoreType.CONFIGURATION, getInterfaceIdentifier(interfaceName)).orElse(null);
152 * Builds the interface identifier.
153 * @param interfaceName the interface name.
154 * @return the interface identifier.
156 public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
157 .interfaces.Interface> getInterfaceIdentifier(String interfaceName) {
158 return InstanceIdentifier.builder(Interfaces.class)
160 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
161 .Interface.class, new InterfaceKey(interfaceName)).build();
165 * Build the interface state.
166 * @param interfaceName the interface name.
167 * @return the interface state.
169 public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
170 .interfaces.state.Interface> buildStateInterfaceId(String interfaceName) {
171 InstanceIdentifier.InstanceIdentifierBuilder<Interface> idBuilder =
172 InstanceIdentifier.builder(InterfacesState.class)
173 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
174 .state.Interface.class,
175 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces
176 .rev140508.interfaces.state.InterfaceKey(interfaceName));
177 return idBuilder.build();
181 * Retrieves the interface state.
182 * @param interfaceName the interface name.
183 * @return the interface state.
185 public org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
186 .@Nullable Interface getInterfaceStateFromOperDS(String interfaceName) {
187 return MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, buildStateInterfaceId(interfaceName), broker)
191 private static List<MatchInfo> getIcmpv6RSMatch(Long elanTag) {
192 List<MatchInfo> matches = new ArrayList<>();
193 matches.add(MatchEthernetType.IPV6);
194 matches.add(MatchIpProtocol.ICMPV6);
195 matches.add(new MatchIcmpv6(Icmpv6Type.ROUTER_SOLICITATION.getValue(), (short) 0));
196 matches.add(new MatchMetadata(MetaDataUtil.getElanTagMetadata(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
200 private List<MatchInfo> getIcmpv6NSMatch(Long elanTag, Ipv6Address ipv6Address) {
201 List<MatchInfo> matches = new ArrayList<>();
202 matches.add(MatchEthernetType.IPV6);
203 matches.add(MatchIpProtocol.ICMPV6);
204 matches.add(new MatchIcmpv6(Icmpv6Type.NEIGHBOR_SOLICITATION.getValue(), (short) 0));
205 matches.add(new MatchIpv6NdTarget(ipv6Address));
206 matches.add(new MatchMetadata(MetaDataUtil.getElanTagMetadata(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
210 private List<MatchInfo> getIcmpv6NAMatch(Long elanTag) {
211 List<MatchInfo> matches = new ArrayList<>();
212 matches.add(MatchEthernetType.IPV6);
213 matches.add(MatchIpProtocol.ICMPV6);
214 matches.add(new MatchIcmpv6(Icmpv6Type.NEIGHBOR_ADVERTISEMENT.getValue(), (short) 0));
215 matches.add(new MatchMetadata(MetaDataUtil.getElanTagMetadata(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
219 private static String getIPv6FlowRef(Uint64 dpId, Long elanTag, String flowType) {
220 return new StringBuilder().append(Ipv6ServiceConstants.FLOWID_PREFIX)
221 .append(dpId).append(Ipv6ServiceConstants.FLOWID_SEPARATOR)
222 .append(elanTag).append(Ipv6ServiceConstants.FLOWID_SEPARATOR)
223 .append(flowType).toString();
226 public void installIcmpv6NsPuntFlow(short tableId, Uint64 dpId, Long elanTag, Ipv6Address ipv6Address,
228 String flowId = getIPv6FlowRef(dpId, elanTag, Ipv6Util.getFormattedIpv6Address(ipv6Address));
230 if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
231 LOG.trace("Removing IPv6 Neighbor Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
233 .addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
234 mdsalUtil.removeFlow(tx, dpId, flowId, tableId);
235 }), LOG, "Error while removing flow={}", flowId);
237 List<ActionInfo> actionsInfos = new ArrayList<>();
238 actionsInfos.add(new ActionPuntToController());
240 int ndPuntTimeout = ipv6serviceConfig.getNeighborDiscoveryPuntTimeout().toJava();
241 if (isNdPuntProtectionEnabled(ndPuntTimeout)) {
242 actionsInfos.add(getLearnActionForNsPuntProtection(ndPuntTimeout));
244 List<InstructionInfo> instructions = Arrays.asList(new InstructionApplyActions(actionsInfos));
245 List<MatchInfo> nsMatch = getIcmpv6NSMatch(elanTag, ipv6Address);
246 FlowEntity nsFlowEntity =
247 MDSALUtil.buildFlowEntity(dpId, tableId, flowId, Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY,
248 "IPv6NS", 0, 0, NwConstants.COOKIE_IPV6_TABLE, nsMatch, instructions);
250 LOG.trace("Installing IPv6 Neighbor Solicitation Flow DpId={}, elanTag={} ipv6Address={}", dpId, elanTag,
251 ipv6Address.getValue());
253 .addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
254 mdsalUtil.addFlow(tx, nsFlowEntity);
255 }), LOG, "Error while adding flow={}", nsFlowEntity);
259 private static String getIPv6OvsFlowRef(short tableId, Uint64 dpId, int lportTag, String ndTargetAddr) {
260 return new StringBuilder().append(Ipv6ServiceConstants.FLOWID_PREFIX)
261 .append(dpId).append(Ipv6ServiceConstants.FLOWID_SEPARATOR)
262 .append(tableId).append(Ipv6ServiceConstants.FLOWID_SEPARATOR)
263 .append(lportTag).append(Ipv6ServiceConstants.FLOWID_SEPARATOR)
264 .append(ndTargetAddr).append(Ipv6ServiceConstants.FLOWID_SEPARATOR)
265 .append(Ipv6ServiceConstants.FLOWID_NS_RESPONDER_SUFFIX).toString();
268 private static String getIPv6OvsFlowRef(short tableId, Uint64 dpId, int lportTag, String ndTargetAddr,
269 String vmMacAddress) {
270 return new StringBuilder().append(Ipv6ServiceConstants.FLOWID_PREFIX)
271 .append(dpId).append(Ipv6ServiceConstants.FLOWID_SEPARATOR)
272 .append(tableId).append(Ipv6ServiceConstants.FLOWID_SEPARATOR)
273 .append(lportTag).append(Ipv6ServiceConstants.FLOWID_SEPARATOR)
274 .append(vmMacAddress).append(Ipv6ServiceConstants.FLOWID_SEPARATOR)
275 .append(ndTargetAddr).append(Ipv6ServiceConstants.FLOWID_SEPARATOR)
276 .append(Ipv6ServiceConstants.FLOWID_NS_RESPONDER_SUFFIX).toString();
279 private ActionLearn getLearnActionForNsPuntProtection(int ndPuntTimeout) {
280 List<FlowMod> flowMods = getFlowModsForIpv6PuntProtection(Icmpv6Type.NEIGHBOR_SOLICITATION);
281 flowMods.add(new ActionLearn.MatchFromField(NxmOfFieldType.NXM_NX_ND_TARGET.getType(),
282 NxmOfFieldType.NXM_NX_ND_TARGET.getType(), NxmOfFieldType.NXM_NX_ND_TARGET.getFlowModHeaderLenInt()));
284 return new ActionLearn(0, ndPuntTimeout, Ipv6ServiceConstants.NS_PUNT_PROTECTION_FLOW_PRIORITY,
285 NwConstants.COOKIE_IPV6_TABLE, 0, NwConstants.IPV6_TABLE, 0, 0, flowMods);
288 public void installIcmpv6RsPuntFlow(short tableId, Uint64 dpId, Long elanTag, int addOrRemove) {
289 if (dpId == null || dpId.equals(Ipv6ServiceConstants.INVALID_DPID)) {
292 String flowId = getIPv6FlowRef(dpId, elanTag, "IPv6RS");
293 if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
294 LOG.trace("Removing IPv6 Router Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
296 .addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
297 mdsalUtil.removeFlow(tx, dpId, flowId, tableId);
298 }), LOG, "Error while removing flow={}", flowId);
300 List<ActionInfo> actionsInfos = new ArrayList<>();
301 // Punt to controller
302 actionsInfos.add(new ActionPuntToController());
304 int rdPuntTimeout = ipv6serviceConfig.getRouterDiscoveryPuntTimeout().toJava();
305 if (isRdPuntProtectionEnabled(rdPuntTimeout)) {
306 actionsInfos.add(getLearnActionForRsPuntProtection(rdPuntTimeout));
308 List<InstructionInfo> instructions = Arrays.asList(new InstructionApplyActions(actionsInfos));
309 List<MatchInfo> routerSolicitationMatch = getIcmpv6RSMatch(elanTag);
310 FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
311 flowId,Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY, "IPv6RS", 0, 0,
312 NwConstants.COOKIE_IPV6_TABLE, routerSolicitationMatch, instructions);
314 LOG.trace("Installing IPv6 Router Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
316 .addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
317 mdsalUtil.addFlow(tx, rsFlowEntity);
318 }), LOG, "Error while adding flow={}", rsFlowEntity);
322 private ActionLearn getLearnActionForRsPuntProtection(int rdPuntTimeout) {
323 return new ActionLearn(0, rdPuntTimeout, Ipv6ServiceConstants.RS_PUNT_PROTECTION_FLOW_PRIORITY,
324 NwConstants.COOKIE_IPV6_TABLE, 0, NwConstants.IPV6_TABLE, 0, 0,
325 getFlowModsForIpv6PuntProtection(Icmpv6Type.ROUTER_SOLICITATION));
328 private List<FlowMod> getFlowModsForIpv6PuntProtection(Icmpv6Type icmpv6Type) {
329 return new ArrayList<>(Arrays.asList(
330 new ActionLearn.MatchFromValue(NwConstants.ETHTYPE_IPV6, NxmOfFieldType.NXM_OF_ETH_TYPE.getType(),
331 NxmOfFieldType.NXM_OF_ETH_TYPE.getFlowModHeaderLenInt()),
332 new ActionLearn.MatchFromValue(IPProtocols.IPV6ICMP.shortValue(),
333 NxmOfFieldType.NXM_OF_IP_PROTO.getType(),
334 NxmOfFieldType.NXM_OF_IP_PROTO.getFlowModHeaderLenInt()),
335 new ActionLearn.MatchFromValue(icmpv6Type.getValue(), NxmOfFieldType.NXM_OF_ICMPv6_TYPE.getType(),
336 NxmOfFieldType.NXM_OF_ICMPv6_TYPE.getFlowModHeaderLenInt()),
337 new ActionLearn.MatchFromField(NxmOfFieldType.NXM_OF_ICMPv6_CODE.getType(),
338 NxmOfFieldType.NXM_OF_ICMPv6_CODE.getType(),
339 NxmOfFieldType.NXM_OF_ICMPv6_CODE.getFlowModHeaderLenInt()),
340 new ActionLearn.MatchFromField(NxmOfFieldType.OXM_OF_METADATA.getType(),
341 MetaDataUtil.METADATA_LPORT_TAG_OFFSET, NxmOfFieldType.OXM_OF_METADATA.getType(),
342 MetaDataUtil.METADATA_LPORT_TAG_OFFSET, MetaDataUtil.METADATA_LPORT_TAG_BITLEN)));
345 private boolean isRdPuntProtectionEnabled(int rdPuntTimeout) {
346 return rdPuntTimeout != 0;
349 private boolean isNdPuntProtectionEnabled(int ndPuntTimeout) {
350 return ndPuntTimeout != 0;
353 public void installIcmpv6NaForwardFlow(short tableId, IVirtualPort vmPort, Uint64 dpId, Long elanTag,
355 List<MatchInfo> matches = getIcmpv6NAMatch(elanTag);
356 List<InstructionInfo> instructions = new ArrayList<>();
357 List<ActionInfo> actionsInfos = new ArrayList<>();
358 actionsInfos.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
359 instructions.add(new InstructionApplyActions(actionsInfos));
361 for (Ipv6Address ipv6Address : vmPort.getIpv6Addresses()) {
362 matches.add(new MatchIpv6Source(ipv6Address.getValue() + NwConstants.IPV6PREFIX));
363 String flowId = getIPv6FlowRef(dpId, elanTag,
364 vmPort.getIntfUUID().getValue() + Ipv6ServiceConstants.FLOWID_SEPARATOR + ipv6Address.getValue());
365 FlowEntity rsFlowEntity =
366 MDSALUtil.buildFlowEntity(dpId, tableId, flowId, Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY,
367 "IPv6NA", 0, 0, NwConstants.COOKIE_IPV6_TABLE, matches, instructions);
368 if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
369 LOG.trace("Removing IPv6 Neighbor Advertisement Flow DpId {}, elanTag {}, ipv6Address {}", dpId,
370 elanTag, ipv6Address.getValue());
371 mdsalUtil.removeFlow(rsFlowEntity);
373 LOG.trace("Installing IPv6 Neighbor Advertisement Flow DpId {}, elanTag {}, ipv6Address {}", dpId,
374 elanTag, ipv6Address.getValue());
375 mdsalUtil.installFlow(rsFlowEntity);
380 public void installIcmpv6NaPuntFlow(short tableId, Ipv6Prefix ipv6Prefix, Uint64 dpId, Long elanTag,
382 List<MatchInfo> naMatch = getIcmpv6NAMatch(elanTag);
383 naMatch.add(new MatchIpv6Source(ipv6Prefix));
385 List<InstructionInfo> instructions = new ArrayList<>();
386 List<ActionInfo> actionsInfos = new ArrayList<>();
387 actionsInfos.add(new ActionPuntToController());
388 actionsInfos.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
389 instructions.add(new InstructionApplyActions(actionsInfos));
391 String flowId = getIPv6FlowRef(dpId, elanTag, "IPv6NA." + ipv6Prefix.getValue());
392 FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
393 flowId, Ipv6ServiceConstants.PUNT_NA_FLOW_PRIORITY,
394 "IPv6NA", 0, 0, NwConstants.COOKIE_IPV6_TABLE, naMatch, instructions);
395 if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
396 LOG.trace("Removing IPv6 Neighbor Advertisement Flow DpId {}, elanTag {}", dpId, elanTag);
397 mdsalUtil.removeFlow(rsFlowEntity);
399 LOG.trace("Installing IPv6 Neighbor Advertisement Flow DpId {}, elanTag {}", dpId, elanTag);
400 mdsalUtil.installFlow(rsFlowEntity);
404 public BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
405 Uint64 cookie, List<Instruction> instructions) {
406 StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie)
407 .setFlowPriority(flowPriority).setInstruction(instructions);
408 return new BoundServicesBuilder().withKey(new BoundServicesKey(servicePriority))
409 .setServiceName(serviceName).setServicePriority(servicePriority)
410 .setServiceType(ServiceTypeFlowBased.class)
411 .addAugmentation(augBuilder.build()).build();
414 private InstanceIdentifier<BoundServices> buildServiceId(String interfaceName,
416 return InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class,
417 new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
418 .child(BoundServices.class, new BoundServicesKey(priority)).build();
421 public void bindIpv6Service(String interfaceName, Long elanTag, short tableId) {
422 int instructionKey = 0;
423 List<Instruction> instructions = new ArrayList<>();
424 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(MetaDataUtil.getElanTagMetadata(elanTag),
425 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
426 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(tableId, ++instructionKey));
427 short serviceIndex = ServiceIndex.getIndex(NwConstants.IPV6_SERVICE_NAME, NwConstants.IPV6_SERVICE_INDEX);
430 getBoundServices(String.format("%s.%s", "ipv6", interfaceName),
431 serviceIndex, Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY,
432 NwConstants.COOKIE_IPV6_TABLE, instructions);
433 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
434 buildServiceId(interfaceName, serviceIndex), serviceInfo);
437 public void unbindIpv6Service(String interfaceName) {
438 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION,
439 buildServiceId(interfaceName, ServiceIndex.getIndex(NwConstants.IPV6_SERVICE_NAME,
440 NwConstants.IPV6_SERVICE_INDEX)));
444 public Uint64 getDpIdFromInterfaceState(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
445 .interfaces.rev140508.interfaces.state.Interface interfaceState) {
447 List<String> ofportIds = interfaceState.getLowerLayerIf();
448 if (ofportIds != null && !ofportIds.isEmpty()) {
449 NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
450 dpId = getDpnIdFromNodeConnectorId(nodeConnectorId);
455 public static Uint64 getDpnIdFromNodeConnectorId(NodeConnectorId nodeConnectorId) {
456 Long dpIdLong = MDSALUtil.getDpnIdFromPortName(nodeConnectorId);
457 return dpIdLong < 0 ? Uint64.ZERO : Uint64.valueOf(dpIdLong);
460 public static long getRemoteBCGroup(long elanTag) {
461 return Ipv6ServiceConstants.ELAN_GID_MIN + elanTag % Ipv6ServiceConstants.ELAN_GID_MIN * 2;
464 public static String buildIpv6MonitorJobKey(String ip) {
468 public static boolean isVmPort(String deviceOwner) {
469 // FIXME: Currently for VM ports, Neutron is sending deviceOwner as empty instead of "compute:nova".
470 // return Ipv6ServiceConstants.DEVICE_OWNER_COMPUTE_NOVA.equalsIgnoreCase(deviceOwner);
471 return Ipv6ServiceConstants.DEVICE_OWNER_COMPUTE_NOVA.equalsIgnoreCase(deviceOwner)
472 || StringUtils.isEmpty(deviceOwner);
475 public static boolean isIpv6Subnet(VirtualSubnet subnet) {
476 if (subnet == null) {
479 return subnet.getIpVersion().equals(Ipv6ServiceConstants.IP_VERSION_V6) ? true : false;
482 public ActionInfo getLearnActionForNsDrop(Long hardTimeoutinMs) {
483 int hardTimeout = (int)(hardTimeoutinMs / 1000);
484 hardTimeout = hardTimeout > 0 ? hardTimeout : 30;
485 List<ActionLearn.FlowMod> flowMods = Arrays.asList(
486 new ActionLearn.MatchFromValue(NwConstants.ETHTYPE_IPV6,
487 NwConstants.NxmOfFieldType.NXM_OF_ETH_TYPE.getType(),
488 NwConstants.NxmOfFieldType.NXM_OF_ETH_TYPE.getFlowModHeaderLenInt()),
489 new ActionLearn.MatchFromValue(IPProtocols.IPV6ICMP.intValue(),
490 NwConstants.NxmOfFieldType.NXM_OF_IP_PROTO.getType(),
491 NwConstants.NxmOfFieldType.NXM_OF_IP_PROTO.getFlowModHeaderLenInt()),
492 new ActionLearn.MatchFromField(NwConstants.NxmOfFieldType.OXM_OF_METADATA.getType(),
493 MetaDataUtil.METADATA_ELAN_TAG_OFFSET, NwConstants.NxmOfFieldType.OXM_OF_METADATA.getType(),
494 MetaDataUtil.METADATA_ELAN_TAG_OFFSET, Ipv6ServiceConstants.ELAN_TAG_LENGTH),
495 new ActionLearn.MatchFromValue(Icmpv6Type.NEIGHBOR_SOLICITATION.getValue(),
496 NwConstants.NxmOfFieldType.OXM_OF_ICMPV6_TYPE.getType(),
497 NwConstants.NxmOfFieldType.OXM_OF_ICMPV6_TYPE.getFlowModHeaderLenInt()),
498 new ActionLearn.MatchFromField(NwConstants.NxmOfFieldType.OXM_OF_IPV6_ND_TARGET.getType(),
499 NwConstants.NxmOfFieldType.OXM_OF_IPV6_ND_TARGET.getType(),
500 NwConstants.NxmOfFieldType.OXM_OF_IPV6_ND_TARGET.getFlowModHeaderLenInt()),
501 new ActionLearn.MatchFromField(NwConstants.NxmOfFieldType.NXM_NX_IPV6_SRC.getType(),
502 NwConstants.NxmOfFieldType.NXM_NX_IPV6_SRC.getType(),
503 NwConstants.NxmOfFieldType.NXM_NX_IPV6_SRC.getFlowModHeaderLenInt()),
504 new ActionLearn.MatchFromField(NwConstants.NxmOfFieldType.NXM_NX_IPV6_DST.getType(),
505 NwConstants.NxmOfFieldType.NXM_NX_IPV6_DST.getType(),
506 NwConstants.NxmOfFieldType.NXM_NX_IPV6_DST.getFlowModHeaderLenInt()));
507 return new ActionLearn(0, hardTimeout, Ipv6ServiceConstants.SLOW_PATH_PROTECTION_PRIORITY,
508 NwConstants.COOKIE_IPV6_TABLE, 0,
509 NwConstants.IPV6_TABLE, 0, 0, flowMods);
513 public void instIcmpv6NsMatchFlow(short tableId, Uint64 dpId, Long elanTag, int lportTag, String vmMacAddress,
514 Ipv6Address ndTargetAddr, int addOrRemove, TypedReadWriteTransaction tx,
515 Boolean isSllOptionSet)
516 throws ExecutionException, InterruptedException {
518 List<ActionInfo> actionsInfos = new ArrayList<>();
519 actionsInfos.add(getLearnActionForNsDrop(ipV6NAConfigHelper.getNsSlowProtectionTimeOutinMs()));
520 actionsInfos.add(new ActionSetIcmpv6Type(Icmpv6Type.NEIGHBOR_ADVERTISEMENT.getValue()));
521 short priority = Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY;
522 if (isSllOptionSet) {
523 actionsInfos.add(new ActionNdOptionType((short)2));
524 priority = Ipv6ServiceConstants.SLLOPTION_SET_FLOW_PRIORITY;
526 List<InstructionInfo> instructions = new ArrayList<>();
527 instructions.add(new InstructionApplyActions(actionsInfos));
528 instructions.add(new InstructionGotoTable(NwConstants.ARP_RESPONDER_TABLE));
530 List<MatchInfo> neighborSolicitationMatch = getIcmpv6NsMatchFlow(elanTag, lportTag, vmMacAddress,
531 ndTargetAddr, isSllOptionSet);
533 FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
534 Boolean.TRUE.equals(isSllOptionSet)
535 ? getIPv6OvsFlowRef(tableId, dpId, lportTag, ndTargetAddr.getValue(), vmMacAddress) :
536 getIPv6OvsFlowRef(tableId, dpId, lportTag, ndTargetAddr.getValue()),priority,
537 "IPv6NS", 0, 0, NwConstants.COOKIE_IPV6_TABLE,
538 neighborSolicitationMatch, instructions);
540 if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
541 LOG.debug("installIcmpv6NsResponderFlow: Removing IPv6 Neighbor Solicitation Flow on "
542 + "DpId {} for NDTraget {}, elanTag {}, lportTag {}", dpId, ndTargetAddr.getValue(),
545 mdsalUtil.removeFlow(tx, rsFlowEntity);
547 LOG.debug("installIcmpv6NsResponderFlow: Installing IPv6 Neighbor Solicitation Flow on "
548 + "DpId {} for NDTraget {} elanTag {}, lportTag {}", dpId, ndTargetAddr.getValue(),
550 mdsalUtil.addFlow(tx, rsFlowEntity);
554 public void installIcmpv6NaResponderFlow(short tableId, Uint64 dpId,
555 Long elanTag, int lportTag, IVirtualPort intf, Ipv6Address ndTargetAddr,
556 String rtrIntMacAddress, int addOrRemove,
557 TypedReadWriteTransaction tx, Boolean isTllOptionSet)
558 throws ExecutionException, InterruptedException {
560 List<MatchInfo> neighborAdvertisementMatch = getIcmpv6NaResponderMatch(elanTag, lportTag, intf.getMacAddress(),
561 ndTargetAddr, isTllOptionSet);
562 short priority = isTllOptionSet ? Ipv6ServiceConstants.SLLOPTION_SET_FLOW_PRIORITY :
563 Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY;
564 if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
565 FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
566 Boolean.TRUE.equals(isTllOptionSet)
567 ? getIPv6OvsFlowRef(tableId, dpId, lportTag, ndTargetAddr.getValue(),
568 intf.getMacAddress()) : getIPv6OvsFlowRef(tableId, dpId, lportTag, ndTargetAddr.getValue()),
569 priority,"IPv6NA", 0, 0, NwConstants.COOKIE_IPV6_TABLE,
570 neighborAdvertisementMatch, null);
571 LOG.debug("installIcmpv6NaResponderFlow: Removing IPv6 Neighbor Advertisement Flow on "
572 + "DpId {} for the NDTraget {}, elanTag {}, lportTag {}", dpId, ndTargetAddr.getValue(),
575 //mdsalUtil.removeFlowToTx(rsFlowEntity, tx);
576 mdsalUtil.removeFlow(tx, rsFlowEntity);
578 List<ActionInfo> actionsInfos = new ArrayList<>();
579 // Move Eth Src to Eth Dst
580 actionsInfos.add(new ActionMoveSourceDestinationEth());
581 actionsInfos.add(new ActionSetFieldEthernetSource(new MacAddress(rtrIntMacAddress)));
583 // Move Ipv6 Src to Ipv6 Dst
584 actionsInfos.add(new ActionMoveSourceDestinationIpv6());
585 actionsInfos.add(new ActionSetSourceIpv6(ndTargetAddr.getValue()));
587 actionsInfos.add(new ActionSetIpv6NdTarget(ndTargetAddr));
588 if (Boolean.TRUE.equals(isTllOptionSet)) {
589 actionsInfos.add(new ActionSetIpv6NdTll(new MacAddress(rtrIntMacAddress)));
590 actionsInfos.add(new ActionNdReserved(Long.parseLong("3758096384")));
592 actionsInfos.add(new ActionNdReserved(Long.parseLong("3221225472")));
594 actionsInfos.add(new ActionNxLoadInPort(Uint64.ZERO));
595 actionsInfos.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
597 List<InstructionInfo> instructions = new ArrayList<>();
598 instructions.add(new InstructionApplyActions(actionsInfos));
600 FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
601 Boolean.TRUE.equals(isTllOptionSet)
602 ? getIPv6OvsFlowRef(tableId, dpId, lportTag, ndTargetAddr.getValue(),
603 intf.getMacAddress()) : getIPv6OvsFlowRef(tableId, dpId, lportTag, ndTargetAddr.getValue()),
604 priority,"IPv6NA", 0, 0, NwConstants.COOKIE_IPV6_TABLE,
605 neighborAdvertisementMatch, instructions);
606 LOG.debug("installIcmpv6NaResponderFlow: Installing IPv6 Neighbor Advertisement Flow on "
607 + "DpId {} for the NDTraget {}, elanTag {}, lportTag {}", dpId, ndTargetAddr.getValue(),
610 mdsalUtil.addFlow(tx, rsFlowEntity);
614 public void installIcmpv6NsDefaultPuntFlow(short tableId, Uint64 dpId, Long elanTag, Ipv6Address ipv6Address,
615 int addOrRemove, TypedReadWriteTransaction tx)
616 throws ExecutionException, InterruptedException {
617 List<MatchInfo> neighborSolicitationMatch = getIcmpv6NSMatch(elanTag, ipv6Address);
618 neighborSolicitationMatch.add(new MatchIpv6Source(UNSPECIFIED_ADDR.getValue() + "/128"));
619 List<InstructionInfo> instructions = new ArrayList<>();
620 List<ActionInfo> actionsInfos = new ArrayList<>();
621 actionsInfos.add(getLearnActionForNsDrop(ipV6NAConfigHelper.getNsSlowProtectionTimeOutinMs()));
622 actionsInfos.add(new ActionPuntToController());
623 instructions.add(new InstructionApplyActions(actionsInfos));
624 FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
625 getIPv6FlowRef(dpId, elanTag, ipv6Address + ".UNSPECIFIED.Switch.NS.Responder"),
626 Ipv6ServiceConstants.FLOW_SUBNET_PRIORITY , "IPv6NS",
627 0, 0, NwConstants.COOKIE_IPV6_TABLE, neighborSolicitationMatch, instructions);
628 if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
629 LOG.debug("installIcmpv6NsDefaultPuntFlow: Removing OVS based NA responder default subnet punt flow on "
630 + "DpId {}, elanTag {} for Unspecified Address", dpId, elanTag);
631 mdsalUtil.removeFlow(tx, rsFlowEntity);
634 LOG.debug("installIcmpv6NsDefaultPuntFlow: Installing OVS based NA responder default subnet punt flow on "
635 + "DpId {}, elanTag {} for Unspecified Address", dpId, elanTag);
636 mdsalUtil.addFlow(tx, rsFlowEntity);
640 private List<MatchInfo> getIcmpv6NsMatchFlow(Long elanTag, int lportTag, String vmMacAddress,
641 Ipv6Address ndTargetAddr,
642 Boolean isSllOptionSet) {
643 List<MatchInfo> matches = new ArrayList<>();
644 matches.add(MatchEthernetType.IPV6);
645 matches.add(MatchIpProtocol.ICMPV6);
646 matches.add(new MatchIcmpv6(Icmpv6Type.NEIGHBOR_SOLICITATION.getValue(), (short) 0));
647 matches.add(new MatchIpv6NdTarget(new Ipv6Address(ndTargetAddr)));
648 if (Boolean.TRUE.equals(isSllOptionSet)) {
649 matches.add(new MatchNdOptionType((short)1));
650 /* matches.add(new MatchIpv6NdSll(new MacAddress(vmMacAddress))); */
652 matches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag, lportTag),
653 ElanHelper.getElanMetadataMask()));
657 private List<MatchInfo> getIcmpv6NaResponderMatch(Long elanTag, int lportTag, String vmMacAddress,
658 Ipv6Address ndTarget, Boolean isNdOptionTypeSet) {
659 List<MatchInfo> matches = new ArrayList<>();
660 matches.add(MatchEthernetType.IPV6);
661 matches.add(MatchIpProtocol.ICMPV6);
662 matches.add(new MatchIcmpv6(Icmpv6Type.NEIGHBOR_ADVERTISEMENT.getValue(), (short) 0));
663 matches.add(new MatchIpv6NdTarget(new Ipv6Address(ndTarget)));
664 if (Boolean.TRUE.equals(isNdOptionTypeSet)) {
665 matches.add(new MatchNdOptionType((short)2));
667 matches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag, lportTag),
668 ElanHelper.getElanMetadataMask()));