2 * Copyright © 2017 Ericsson, 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.sfc.classifier.providers;
11 import com.google.common.net.InetAddresses;
12 import java.math.BigInteger;
13 import java.util.Collections;
14 import java.util.List;
15 import java.util.Optional;
16 import java.util.concurrent.ExecutionException;
17 import javax.inject.Inject;
18 import javax.inject.Singleton;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
22 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
23 import org.opendaylight.genius.mdsalutil.MDSALUtil;
24 import org.opendaylight.genius.mdsalutil.NwConstants;
25 import org.opendaylight.netvirt.sfc.classifier.utils.OpenFlow13Utils;
26 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.logical.rev160620.DpnIdType;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpnInterfaceListInput;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpnInterfaceListInputBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpnInterfaceListOutput;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEndpointIpForDpnInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEndpointIpForDpnInputBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEndpointIpForDpnOutput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetNodeconnectorIdFromInterfaceInput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetNodeconnectorIdFromInterfaceInputBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetNodeconnectorIdFromInterfaceOutput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.bound.services.instruction.instruction.apply.actions._case.apply.actions.action.action.ServiceBindingNxActionRegLoadApplyActionsCaseBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeBase;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeVxlan;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Options;
63 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
64 import org.opendaylight.yangtools.yang.common.RpcResult;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
69 public class GeniusProvider {
71 private final DataBroker dataBroker;
72 private final IInterfaceManager interfaceMgr;
73 private final OdlInterfaceRpcService interfaceManagerRpcService;
74 private static final Logger LOG = LoggerFactory.getLogger(GeniusProvider.class);
75 public static final String OPTION_KEY_EXTS = "exts";
76 public static final String OPTION_VALUE_EXTS_GPE = "gpe";
79 public GeniusProvider(final DataBroker dataBroker, final RpcProviderRegistry rpcProviderRegistry,
80 final IInterfaceManager interfaceMgr) {
81 this.dataBroker = dataBroker;
82 this.interfaceMgr = interfaceMgr;
83 this.interfaceManagerRpcService = rpcProviderRegistry.getRpcService(OdlInterfaceRpcService.class);
86 // Package local constructor used by UT for simplification
87 GeniusProvider(final DataBroker dataBroker, final OdlInterfaceRpcService interfaceManagerRpcService,
88 final IInterfaceManager interfaceMgr) {
89 this.dataBroker = dataBroker;
90 this.interfaceMgr = interfaceMgr;
91 this.interfaceManagerRpcService = interfaceManagerRpcService;
94 public void bindPortOnIngressClassifier(String interfaceName) {
96 getBindServiceId(NwConstants.SFC_CLASSIFIER_INDEX, interfaceName, true),
97 NwConstants.SFC_CLASSIFIER_INDEX,
98 NwConstants.SFC_CLASSIFIER_SERVICE_NAME,
99 NwConstants.SFC_SERVICE_INDEX,
100 NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE,
101 OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_COOKIE);
104 public void bindPortOnEgressClassifier(String interfaceName, String destinationIp) {
106 getBindServiceId(NwConstants.EGRESS_SFC_CLASSIFIER_SERVICE_INDEX, interfaceName, false),
107 NwConstants.EGRESS_SFC_CLASSIFIER_SERVICE_INDEX,
108 NwConstants.EGRESS_SFC_CLASSIFIER_SERVICE_NAME,
109 NwConstants.EGRESS_SFC_CLASSIFIER_SERVICE_INDEX,
110 NwConstants.EGRESS_SFC_CLASSIFIER_FILTER_TABLE,
111 OpenFlow13Provider.EGRESS_CLASSIFIER_FILTER_COOKIE,
112 Collections.singletonList(
113 createServiceBindingActionNxLoadReg0(
114 InetAddresses.coerceToInteger(
115 InetAddresses.forString(destinationIp)) & 0xffffffffL,
120 public void unbindPortOnIngressClassifier(String interfaceName) {
121 unbindService(getBindServiceId(NwConstants.SFC_CLASSIFIER_INDEX, interfaceName, true));
124 public void unbindPortOnEgressClassifier(String interfaceName) {
125 unbindService(getBindServiceId(NwConstants.EGRESS_SFC_CLASSIFIER_SERVICE_INDEX, interfaceName, false));
128 public Optional<NodeId> getNodeIdFromLogicalInterface(String logicalInterface) {
129 Optional<DpnIdType> dpnId = getDpnIdFromInterfaceName(logicalInterface);
131 if (!dpnId.isPresent()) {
132 LOG.warn("getNodeIdFromLogicalInterface empty dpnId for logicalInterface [{}]", logicalInterface);
133 return Optional.empty();
136 return getNodeIdFromDpnId(dpnId.get());
139 public Optional<NodeId> getNodeIdFromDpnId(DpnIdType dpnId) {
141 return Optional.empty();
144 if (dpnId.getValue() == null) {
145 return Optional.empty();
148 return Optional.of(new NodeId("openflow:" + dpnId.getValue()));
151 public Optional<String> getIpFromInterfaceName(String interfaceName) {
152 Optional<DpnIdType> dpnId = getDpnIdFromInterfaceName(interfaceName);
153 if (!dpnId.isPresent()) {
154 LOG.warn("getIpFromInterfaceName empty dpnId for interfaceName [{}]", interfaceName);
155 return Optional.empty();
158 List<IpAddress> ipList = getIpFromDpnId(dpnId.get());
159 if (ipList.isEmpty()) {
160 LOG.warn("getIpFromInterfaceName empty ipList for interfaceName [{}]", interfaceName);
161 return Optional.empty();
164 // TODO need to figure out why it returns a list, using first entry for now
165 return Optional.ofNullable(ipList.get(0).getIpv4Address().getValue());
168 // TODO Should better use the Genius InterfaceManager to avoid duplicate code
169 // https://bugs.opendaylight.org/show_bug.cgi?id=8127
170 public List<IpAddress> getIpFromDpnId(DpnIdType dpnid) {
171 GetEndpointIpForDpnInputBuilder builder = new GetEndpointIpForDpnInputBuilder();
172 builder.setDpid(dpnid.getValue());
173 GetEndpointIpForDpnInput input = builder.build();
175 if (interfaceManagerRpcService == null) {
176 LOG.error("getIpFromDpnId({}) failed (service couldn't be retrieved)", input);
177 return Collections.emptyList();
181 LOG.debug("getIpFromDpnId: invoking rpc");
182 RpcResult<GetEndpointIpForDpnOutput> output = interfaceManagerRpcService.getEndpointIpForDpn(input).get();
183 if (!output.isSuccessful()) {
184 LOG.error("getIpFromDpnId({}) failed: {}", input, output);
185 return Collections.emptyList();
187 List<IpAddress> localIps = output.getResult().getLocalIps();
188 LOG.debug("getDpnIdFromInterfaceName({}) succeeded: {}", input, output);
189 if (localIps != null) {
192 } catch (InterruptedException | ExecutionException e) {
193 LOG.error("getDpnIdFromInterfaceName failed to retrieve target interface name: ", e);
196 return Collections.emptyList();
199 public Optional<DpnIdType> getDpnIdFromInterfaceName(String interfaceName) {
200 LOG.debug("getDpnIdFromInterfaceName: starting (logical interface={})", interfaceName);
201 GetDpidFromInterfaceInputBuilder builder = new GetDpidFromInterfaceInputBuilder();
202 builder.setIntfName(interfaceName);
203 GetDpidFromInterfaceInput input = builder.build();
205 if (interfaceManagerRpcService == null) {
206 LOG.error("getDpnIdFromInterfaceName({}) failed (service couldn't be retrieved)", input);
207 return Optional.empty();
211 LOG.debug("getDpnIdFromInterfaceName: invoking rpc");
212 RpcResult<GetDpidFromInterfaceOutput> output = interfaceManagerRpcService.getDpidFromInterface(input).get();
213 if (!output.isSuccessful()) {
214 LOG.error("getDpnIdFromInterfaceName({}) failed: {}", input, output);
215 return Optional.empty();
218 BigInteger dpnId = output.getResult().getDpid();
220 return Optional.empty();
222 LOG.debug("getDpnIdFromInterfaceName({}) succeeded: {}", input, output);
224 return Optional.of(new DpnIdType(dpnId));
225 } catch (InterruptedException | ExecutionException e) {
226 LOG.error("getDpnIdFromInterfaceName failed to retrieve target interface name: ", e);
229 return Optional.empty();
232 public Optional<String> getNodeConnectorIdFromInterfaceName(String interfaceName) {
233 LOG.debug("getDpnIdFromInterfaceName: starting (logical interface={})", interfaceName);
234 GetNodeconnectorIdFromInterfaceInputBuilder builder = new GetNodeconnectorIdFromInterfaceInputBuilder();
235 builder.setIntfName(interfaceName);
236 GetNodeconnectorIdFromInterfaceInput input = builder.build();
238 if (interfaceManagerRpcService == null) {
239 LOG.error("getNodeConnectorIdFromInterfaceName({}) failed (service couldn't be retrieved)", input);
240 return Optional.empty();
244 LOG.debug("getNodeConnectorIdFromInterfaceName: invoking rpc");
245 RpcResult<GetNodeconnectorIdFromInterfaceOutput> output =
246 interfaceManagerRpcService.getNodeconnectorIdFromInterface(input).get();
247 if (!output.isSuccessful()) {
248 LOG.error("getNodeConnectorIdFromInterfaceName({}) failed: {}", input, output);
249 return Optional.empty();
251 NodeConnectorId nodeConnId = output.getResult().getNodeconnectorId();
252 if (nodeConnId == null) {
253 return Optional.empty();
255 LOG.debug("getNodeConnectorIdFromInterfaceName({}) succeeded: {}", input, output);
257 return Optional.ofNullable(nodeConnId.getValue());
258 } catch (InterruptedException | ExecutionException e) {
259 LOG.error("getNodeConnectorIdFromInterfaceName failed to retrieve target interface name: ", e);
262 return Optional.empty();
265 public Optional<Long> getEgressVxlanPortForNode(BigInteger dpnId) {
266 List<OvsdbTerminationPointAugmentation> tpList = interfaceMgr.getTunnelPortsOnBridge(dpnId);
267 if (tpList == null) {
268 // Most likely the bridge doesnt exist for this dpnId
269 LOG.warn("getEgressVxlanPortForNode Tunnel Port TerminationPoint list not available for dpnId [{}]",
271 return Optional.empty();
274 for (OvsdbTerminationPointAugmentation tp : tpList) {
276 // Technically we should never have a list with NULL entries, but
277 // in a preliminary version of interfaceMgr.getTunnelPortsOnBridge()
278 // we were getting a list where all termination point entries were
279 // null. Leaving this check for now for protection.
280 LOG.error("getEgressVxlanPortForNode received a NULL termination point from tpList on dpnId [{}]",
285 Class<? extends InterfaceTypeBase> ifType = tp.getInterfaceType();
286 if (ifType.equals(InterfaceTypeVxlan.class)) {
287 List<Options> tpOptions = tp.getOptions();
288 for (Options tpOption : tpOptions) {
289 // From the VXLAN Tunnels, we want the one with the GPE option set
290 if (tpOption.getKey().getOption().equals(OPTION_KEY_EXTS)) {
291 if (tpOption.getValue().equals(OPTION_VALUE_EXTS_GPE)) {
292 return Optional.ofNullable(tp.getOfport());
299 LOG.warn("getEgressVxlanPortForNode no Vxgpe tunnel ports available for dpnId [{}]", dpnId);
301 return Optional.empty();
304 public List<String> getInterfacesFromNode(NodeId nodeId) {
305 // getPortsOnBridge() only returns Tunnel ports, so instead using getDpnInterfaceList.
306 GetDpnInterfaceListInputBuilder inputBuilder = new GetDpnInterfaceListInputBuilder();
307 inputBuilder.setDpid(BigInteger.valueOf(Long.valueOf(nodeId.getValue().split(":")[1])));
308 GetDpnInterfaceListInput input = inputBuilder.build();
311 LOG.debug("getInterfacesFromNode: invoking rpc");
312 RpcResult<GetDpnInterfaceListOutput> output =
313 interfaceManagerRpcService.getDpnInterfaceList(input).get();
314 if (!output.isSuccessful()) {
315 LOG.error("getInterfacesFromNode({}) failed: {}", input, output);
316 return Collections.emptyList();
318 LOG.debug("getInterfacesFromNode({}) succeeded: {}", input, output);
319 return output.getResult().getInterfacesList();
320 } catch (InterruptedException | ExecutionException e) {
321 LOG.error("getInterfacesFromNode failed to retrieve target interface name: ", e);
324 return Collections.emptyList();
327 public InstanceIdentifier<BoundServices> getBindServiceId(short serviceId, String interfaceName,
329 ServicesInfoKey servicesInfoKey = isIngress
330 ? new ServicesInfoKey(interfaceName, ServiceModeIngress.class) :
331 new ServicesInfoKey(interfaceName, ServiceModeEgress.class);
332 InstanceIdentifier<BoundServices> id = InstanceIdentifier.builder(ServiceBindings.class)
333 .child(ServicesInfo.class, servicesInfoKey)
334 .child(BoundServices.class, new BoundServicesKey(serviceId)).build();
339 private void bindService(InstanceIdentifier<BoundServices> id, short serviceId, String serviceName,
340 int servicePriority, short serviceDestTable, BigInteger serviceTableCookie) {
348 Collections.emptyList());
351 private void bindService(InstanceIdentifier<BoundServices> id, short serviceId, String serviceName,
352 int servicePriority, short serviceDestTable, BigInteger serviceTableCookie, List<Action> extraActions) {
353 InstructionsBuilder isb = extraActions.isEmpty()
354 ? new InstructionsBuilder()
355 : OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(extraActions);
356 isb = OpenFlow13Utils.appendGotoTableInstruction(isb, serviceDestTable);
357 StypeOpenflow stypeOpenflow = new StypeOpenflowBuilder()
358 .setFlowCookie(serviceTableCookie)
359 .setFlowPriority(servicePriority)
360 .setInstruction(isb.build().getInstruction())
362 BoundServices boundServices = new BoundServicesBuilder().setServiceName(serviceName)
363 .setServicePriority(serviceId).setServiceType(ServiceTypeFlowBased.class)
364 .addAugmentation(StypeOpenflow.class, stypeOpenflow).build();
365 LOG.info("Binding Service ID [{}] name [{}] priority [{}] table [{}] cookie [{}] extraActions [{}]",
366 serviceId, serviceName, servicePriority, serviceDestTable, serviceTableCookie, extraActions);
368 MDSALUtil.syncWrite(this.dataBroker, LogicalDatastoreType.CONFIGURATION, id, boundServices);
371 private void unbindService(InstanceIdentifier<BoundServices> id) {
372 MDSALUtil.syncDelete(this.dataBroker, LogicalDatastoreType.CONFIGURATION, id);
375 public Optional<String> getRemoteIpAddress(String interfaceName) {
376 return Optional.ofNullable(interfaceMgr.getInterfaceInfoFromConfigDataStore(interfaceName))
377 .map(anInterface -> anInterface.getAugmentation(IfTunnel.class))
378 .map(IfTunnel::getTunnelDestination)
379 .map(IpAddress::getIpv4Address)
380 .map(Ipv4Address::getValue);
383 public static Action createServiceBindingActionNxLoadReg0(long value, int order) {
384 return OpenFlow13Utils.createAction(
385 new ServiceBindingNxActionRegLoadApplyActionsCaseBuilder()
386 .setNxRegLoad(OpenFlow13Utils.createNxLoadReg0(value))