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.rpcs.rev160406.get.dpn._interface.list.output.Interfaces;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
57 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;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeBase;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeVxlan;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Options;
64 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
65 import org.opendaylight.yangtools.yang.common.RpcResult;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
70 public class GeniusProvider {
71 private static final Logger LOG = LoggerFactory.getLogger(GeniusProvider.class);
72 public static final String OPTION_KEY_EXTS = "exts";
73 public static final String OPTION_VALUE_EXTS_GPE = "gpe";
75 private final DataBroker dataBroker;
76 private final IInterfaceManager interfaceMgr;
77 private final OdlInterfaceRpcService interfaceManagerRpcService;
80 public GeniusProvider(final DataBroker dataBroker, final RpcProviderRegistry rpcProviderRegistry,
81 final IInterfaceManager interfaceMgr) {
82 this.dataBroker = dataBroker;
83 this.interfaceMgr = interfaceMgr;
84 this.interfaceManagerRpcService = rpcProviderRegistry.getRpcService(OdlInterfaceRpcService.class);
87 // Package local constructor used by UT for simplification
88 GeniusProvider(final DataBroker dataBroker, final OdlInterfaceRpcService interfaceManagerRpcService,
89 final IInterfaceManager interfaceMgr) {
90 this.dataBroker = dataBroker;
91 this.interfaceMgr = interfaceMgr;
92 this.interfaceManagerRpcService = interfaceManagerRpcService;
95 public void bindPortOnIngressClassifier(String interfaceName) {
97 getBindServiceId(NwConstants.SFC_CLASSIFIER_INDEX, interfaceName, true),
98 NwConstants.SFC_CLASSIFIER_INDEX,
99 NwConstants.SFC_CLASSIFIER_SERVICE_NAME,
100 NwConstants.SFC_SERVICE_INDEX,
101 NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE,
102 OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_COOKIE);
105 public void bindPortOnEgressClassifier(String interfaceName, String destinationIp) {
107 getBindServiceId(NwConstants.EGRESS_SFC_CLASSIFIER_SERVICE_INDEX, interfaceName, false),
108 NwConstants.EGRESS_SFC_CLASSIFIER_SERVICE_INDEX,
109 NwConstants.EGRESS_SFC_CLASSIFIER_SERVICE_NAME,
110 NwConstants.EGRESS_SFC_CLASSIFIER_SERVICE_INDEX,
111 NwConstants.EGRESS_SFC_CLASSIFIER_FILTER_TABLE,
112 OpenFlow13Provider.EGRESS_CLASSIFIER_FILTER_COOKIE,
113 Collections.singletonList(
114 createServiceBindingActionNxLoadReg0(
115 InetAddresses.coerceToInteger(
116 InetAddresses.forString(destinationIp)) & 0xffffffffL,
121 public void unbindPortOnIngressClassifier(String interfaceName) {
122 unbindService(getBindServiceId(NwConstants.SFC_CLASSIFIER_INDEX, interfaceName, true));
125 public void unbindPortOnEgressClassifier(String interfaceName) {
126 unbindService(getBindServiceId(NwConstants.EGRESS_SFC_CLASSIFIER_SERVICE_INDEX, interfaceName, false));
129 public Optional<NodeId> getNodeIdFromLogicalInterface(String logicalInterface) {
130 Optional<DpnIdType> dpnId = getDpnIdFromInterfaceName(logicalInterface);
132 if (!dpnId.isPresent()) {
133 LOG.warn("getNodeIdFromLogicalInterface empty dpnId for logicalInterface [{}]", logicalInterface);
134 return Optional.empty();
137 return getNodeIdFromDpnId(dpnId.get());
140 public Optional<NodeId> getNodeIdFromDpnId(DpnIdType dpnId) {
142 return Optional.empty();
145 if (dpnId.getValue() == null) {
146 return Optional.empty();
149 return Optional.of(new NodeId("openflow:" + dpnId.getValue()));
152 // TODO Should better use the Genius InterfaceManager to avoid duplicate code
153 // https://bugs.opendaylight.org/show_bug.cgi?id=8127
154 public Optional<String> getIpFromDpnId(DpnIdType dpnid) {
155 GetEndpointIpForDpnInputBuilder builder = new GetEndpointIpForDpnInputBuilder();
156 builder.setDpid(dpnid.getValue());
157 GetEndpointIpForDpnInput input = builder.build();
159 if (interfaceManagerRpcService == null) {
160 LOG.error("getIpFromDpnId({}) failed (service couldn't be retrieved)", input);
161 return Optional.empty();
165 LOG.debug("getIpFromDpnId: invoking rpc");
166 RpcResult<GetEndpointIpForDpnOutput> output = interfaceManagerRpcService.getEndpointIpForDpn(input).get();
167 if (!output.isSuccessful()) {
168 LOG.error("getIpFromDpnId({}) failed: {}", input, output);
169 return Optional.empty();
171 LOG.debug("getDpnIdFromInterfaceName({}) succeeded: {}", input, output);
172 List<IpAddress> localIps = output.getResult().getLocalIps();
174 // TODO need to figure out why it returns a list, using first entry for now
175 return Optional.ofNullable(localIps)
176 .filter(ipAddresses -> !ipAddresses.isEmpty())
177 .map(ipAddresses -> ipAddresses.get(0))
178 .map(IpAddress::getIpv4Address)
179 .map(Ipv4Address::getValue);
180 } catch (InterruptedException | ExecutionException e) {
181 LOG.error("getDpnIdFromInterfaceName failed to retrieve target interface name: ", e);
184 return Optional.empty();
187 public Optional<DpnIdType> getDpnIdFromInterfaceName(String interfaceName) {
188 LOG.debug("getDpnIdFromInterfaceName: starting (logical interface={})", interfaceName);
189 GetDpidFromInterfaceInputBuilder builder = new GetDpidFromInterfaceInputBuilder();
190 builder.setIntfName(interfaceName);
191 GetDpidFromInterfaceInput input = builder.build();
193 if (interfaceManagerRpcService == null) {
194 LOG.error("getDpnIdFromInterfaceName({}) failed (service couldn't be retrieved)", input);
195 return Optional.empty();
199 LOG.debug("getDpnIdFromInterfaceName: invoking rpc");
200 RpcResult<GetDpidFromInterfaceOutput> output = interfaceManagerRpcService.getDpidFromInterface(input).get();
201 if (!output.isSuccessful()) {
202 LOG.error("getDpnIdFromInterfaceName({}) failed: {}", input, output);
203 return Optional.empty();
206 BigInteger dpnId = output.getResult().getDpid();
208 return Optional.empty();
210 LOG.debug("getDpnIdFromInterfaceName({}) succeeded: {}", input, output);
212 return Optional.of(new DpnIdType(dpnId));
213 } catch (InterruptedException | ExecutionException e) {
214 LOG.error("getDpnIdFromInterfaceName failed to retrieve target interface name: ", e);
217 return Optional.empty();
220 public Optional<String> getNodeConnectorIdFromInterfaceName(String interfaceName) {
221 LOG.debug("getDpnIdFromInterfaceName: starting (logical interface={})", interfaceName);
222 GetNodeconnectorIdFromInterfaceInputBuilder builder = new GetNodeconnectorIdFromInterfaceInputBuilder();
223 builder.setIntfName(interfaceName);
224 GetNodeconnectorIdFromInterfaceInput input = builder.build();
226 if (interfaceManagerRpcService == null) {
227 LOG.error("getNodeConnectorIdFromInterfaceName({}) failed (service couldn't be retrieved)", input);
228 return Optional.empty();
232 LOG.debug("getNodeConnectorIdFromInterfaceName: invoking rpc");
233 RpcResult<GetNodeconnectorIdFromInterfaceOutput> output =
234 interfaceManagerRpcService.getNodeconnectorIdFromInterface(input).get();
235 if (!output.isSuccessful()) {
236 LOG.error("getNodeConnectorIdFromInterfaceName({}) failed: {}", input, output);
237 return Optional.empty();
239 NodeConnectorId nodeConnId = output.getResult().getNodeconnectorId();
240 if (nodeConnId == null) {
241 return Optional.empty();
243 LOG.debug("getNodeConnectorIdFromInterfaceName({}) succeeded: {}", input, output);
245 return Optional.ofNullable(nodeConnId.getValue());
246 } catch (InterruptedException | ExecutionException e) {
247 LOG.error("getNodeConnectorIdFromInterfaceName failed to retrieve target interface name: ", e);
250 return Optional.empty();
253 public Optional<Long> getEgressVxlanPortForNode(BigInteger dpnId) {
254 List<OvsdbTerminationPointAugmentation> tpList = interfaceMgr.getTunnelPortsOnBridge(dpnId);
255 if (tpList == null) {
256 // Most likely the bridge doesnt exist for this dpnId
257 LOG.warn("getEgressVxlanPortForNode Tunnel Port TerminationPoint list not available for dpnId [{}]",
259 return Optional.empty();
262 for (OvsdbTerminationPointAugmentation tp : tpList) {
264 // Technically we should never have a list with NULL entries, but
265 // in a preliminary version of interfaceMgr.getTunnelPortsOnBridge()
266 // we were getting a list where all termination point entries were
267 // null. Leaving this check for now for protection.
268 LOG.error("getEgressVxlanPortForNode received a NULL termination point from tpList on dpnId [{}]",
273 Class<? extends InterfaceTypeBase> ifType = tp.getInterfaceType();
274 if (ifType.equals(InterfaceTypeVxlan.class)) {
275 List<Options> tpOptions = tp.getOptions();
276 for (Options tpOption : tpOptions) {
277 // From the VXLAN Tunnels, we want the one with the GPE option set
278 if (tpOption.key().getOption().equals(OPTION_KEY_EXTS)) {
279 if (tpOption.getValue().equals(OPTION_VALUE_EXTS_GPE)) {
280 return Optional.ofNullable(tp.getOfport());
287 LOG.warn("getEgressVxlanPortForNode no Vxgpe tunnel ports available for dpnId [{}]", dpnId);
289 return Optional.empty();
292 public List<Interfaces> getInterfacesFromNode(NodeId nodeId) {
293 // getPortsOnBridge() only returns Tunnel ports, so instead using getDpnInterfaceList.
294 GetDpnInterfaceListInputBuilder inputBuilder = new GetDpnInterfaceListInputBuilder();
295 inputBuilder.setDpid(BigInteger.valueOf(Long.parseLong(nodeId.getValue().split(":")[1])));
296 GetDpnInterfaceListInput input = inputBuilder.build();
299 LOG.debug("getInterfacesFromNode: invoking rpc");
300 RpcResult<GetDpnInterfaceListOutput> output =
301 interfaceManagerRpcService.getDpnInterfaceList(input).get();
302 if (!output.isSuccessful()) {
303 LOG.error("getInterfacesFromNode({}) failed: {}", input, output);
304 return Collections.emptyList();
306 LOG.debug("getInterfacesFromNode({}) succeeded: {}", input, output);
307 return output.getResult().getInterfaces();
308 } catch (InterruptedException | ExecutionException e) {
309 LOG.error("getInterfacesFromNode failed to retrieve target interface name: ", e);
312 return Collections.emptyList();
315 public InstanceIdentifier<BoundServices> getBindServiceId(short serviceId, String interfaceName,
317 ServicesInfoKey servicesInfoKey = isIngress
318 ? new ServicesInfoKey(interfaceName, ServiceModeIngress.class) :
319 new ServicesInfoKey(interfaceName, ServiceModeEgress.class);
320 InstanceIdentifier<BoundServices> id = InstanceIdentifier.builder(ServiceBindings.class)
321 .child(ServicesInfo.class, servicesInfoKey)
322 .child(BoundServices.class, new BoundServicesKey(serviceId)).build();
327 private void bindService(InstanceIdentifier<BoundServices> id, short serviceId, String serviceName,
328 int servicePriority, short serviceDestTable, BigInteger serviceTableCookie) {
336 Collections.emptyList());
339 private void bindService(InstanceIdentifier<BoundServices> id, short serviceId, String serviceName,
340 int servicePriority, short serviceDestTable, BigInteger serviceTableCookie, List<Action> extraActions) {
341 InstructionsBuilder isb = extraActions.isEmpty()
342 ? new InstructionsBuilder()
343 : OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(extraActions);
344 isb = OpenFlow13Utils.appendGotoTableInstruction(isb, serviceDestTable);
345 StypeOpenflow stypeOpenflow = new StypeOpenflowBuilder()
346 .setFlowCookie(serviceTableCookie)
347 .setFlowPriority(servicePriority)
348 .setInstruction(isb.build().getInstruction())
350 BoundServices boundServices = new BoundServicesBuilder().setServiceName(serviceName)
351 .setServicePriority(serviceId).setServiceType(ServiceTypeFlowBased.class)
352 .addAugmentation(StypeOpenflow.class, stypeOpenflow).build();
353 LOG.info("Binding Service ID [{}] name [{}] priority [{}] table [{}] cookie [{}] extraActions [{}]",
354 serviceId, serviceName, servicePriority, serviceDestTable, serviceTableCookie, extraActions);
356 MDSALUtil.syncWrite(this.dataBroker, LogicalDatastoreType.CONFIGURATION, id, boundServices);
359 private void unbindService(InstanceIdentifier<BoundServices> id) {
360 MDSALUtil.syncDelete(this.dataBroker, LogicalDatastoreType.CONFIGURATION, id);
363 public Optional<String> getRemoteIpAddress(String interfaceName) {
364 return Optional.ofNullable(interfaceMgr.getInterfaceInfoFromConfigDataStore(interfaceName))
365 .map(anInterface -> anInterface.augmentation(IfTunnel.class))
366 .map(IfTunnel::getTunnelDestination)
367 .map(IpAddress::getIpv4Address)
368 .map(Ipv4Address::getValue);
371 public static Action createServiceBindingActionNxLoadReg0(long value, int order) {
372 return OpenFlow13Utils.createAction(
373 new ServiceBindingNxActionRegLoadApplyActionsCaseBuilder()
374 .setNxRegLoad(OpenFlow13Utils.createNxLoadReg0(value))