2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
\r
4 * This program and the accompanying materials are made available under the
\r
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
\r
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
\r
9 package org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.processors;
\r
11 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
\r
12 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
\r
13 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
\r
14 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
\r
15 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
\r
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
\r
17 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
\r
18 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
\r
19 import org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.SocketInfo;
\r
20 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
\r
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
\r
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
\r
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
\r
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
\r
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.UniqueId;
\r
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.Mappings;
\r
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.GbpByNeutronMappings;
\r
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.BaseEndpointsByPorts;
\r
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.base.endpoints.by.ports.BaseEndpointByPort;
\r
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.base.endpoints.by.ports.BaseEndpointByPortKey;
\r
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
\r
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
\r
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointBuilder;
\r
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointKey;
\r
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.LoopbackCase;
\r
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.LoopbackCaseBuilder;
\r
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.TapCase;
\r
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.TapCaseBuilder;
\r
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.VhostUserCaseBuilder;
\r
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
\r
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.Routers;
\r
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
\r
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.RouterKey;
\r
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
\r
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
\r
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
\r
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.PortKey;
\r
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
\r
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
\r
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
\r
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey;
\r
52 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
\r
53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
\r
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
\r
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
\r
56 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
\r
57 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
\r
58 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
\r
59 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
\r
60 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
\r
61 import org.slf4j.Logger;
\r
62 import org.slf4j.LoggerFactory;
\r
64 import com.google.common.annotations.VisibleForTesting;
\r
65 import com.google.common.base.Optional;
\r
67 import java.util.List;
\r
69 public class PortHandler implements TransactionChainListener {
\r
71 private static final Logger LOG = LoggerFactory.getLogger(MappingProvider.class);
\r
73 private static final String COMPUTE_OWNER = "compute";
\r
74 private static final String DHCP_OWNER = "dhcp";
\r
75 private static final String ROUTER_OWNER = "network:router_interface";
\r
76 private static final String[] SUPPORTED_DEVICE_OWNERS = {COMPUTE_OWNER, DHCP_OWNER, ROUTER_OWNER};
\r
77 private static final String VHOST_USER = "vhostuser";
\r
78 private static final String NETCONF_TOPOLOGY_ID = "topology-netconf";
\r
79 private static final String VPP_INTERFACE_NAME_PREFIX = "neutron_port_";
\r
80 private static final String TAP_PORT_NAME_PREFIX = "tap";
\r
81 private static final String RT_PORT_NAME_PREFIX = "qr-";
\r
83 private BindingTransactionChain transactionChain;
\r
84 private DataBroker dataBroker;
\r
85 private SocketInfo socketInfo;
\r
87 PortHandler(DataBroker dataBroker, SocketInfo socketInfo) {
\r
88 this.dataBroker = dataBroker;
\r
89 this.socketInfo = socketInfo;
\r
90 transactionChain = this.dataBroker.createTransactionChain(this);
\r
93 void processCreated(Port port) {
\r
94 ReadOnlyTransaction rTx = transactionChain.newReadOnlyTransaction();
\r
95 Optional<BaseEndpointByPort> optBaseEpByPort = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
\r
96 createBaseEpByPortIid(port.getUuid()), rTx);
\r
98 if (!optBaseEpByPort.isPresent()) {
\r
101 processCreatedData(port, optBaseEpByPort.get());
\r
104 void processCreated(BaseEndpointByPort bebp) {
\r
105 ReadOnlyTransaction rTx = transactionChain.newReadOnlyTransaction();
\r
106 Optional<Port> optPort = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
\r
107 createPortIid(bebp.getPortId()), rTx);
\r
109 if (!optPort.isPresent()) {
\r
112 processCreatedData(optPort.get(), bebp);
\r
116 void processCreatedData(Port port, BaseEndpointByPort bebp) {
\r
117 if (isValidVhostUser(port)) {
\r
118 VppEndpoint vppEp = buildVppEndpoint(port, bebp);
\r
119 writeVppEndpoint(createVppEndpointIid(vppEp.getKey()), vppEp);
\r
120 LOG.debug("Created vpp-endpoint {}", vppEp);
\r
124 private boolean isValidVhostUser(Port port) {
\r
125 PortBindingExtension portBindingExt = port.getAugmentation(PortBindingExtension.class);
\r
126 if (portBindingExt != null) {
\r
127 String vifType = portBindingExt.getVifType();
\r
128 String deviceOwner = port.getDeviceOwner();
\r
129 if (vifType != null && deviceOwner != null) {
\r
130 if (vifType.contains(VHOST_USER)) {
\r
131 for (String supportedDeviceOwner : SUPPORTED_DEVICE_OWNERS) {
\r
132 if (deviceOwner.contains(supportedDeviceOwner)) {
\r
142 void processUpdated(Port original, Port delta) {
\r
143 if (isValidVhostUser(original)) {
\r
144 ReadOnlyTransaction rTx = transactionChain.newReadOnlyTransaction();
\r
145 Optional<BaseEndpointByPort> optBebp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
\r
146 createBaseEpByPortIid(original.getUuid()), rTx);
\r
148 if (!optBebp.isPresent()) {
\r
151 processDeleted(optBebp.get());
\r
153 processCreated(delta);
\r
156 void processDeleted(BaseEndpointByPort bebp) {
\r
157 VppEndpointKey vppEpKey = new VppEndpointKey(bebp.getAddress(), bebp.getAddressType(), bebp.getContextId(),
\r
158 bebp.getContextType());
\r
159 InstanceIdentifier<VppEndpoint> vppEpIid = createVppEndpointIid(vppEpKey);
\r
160 ReadOnlyTransaction rTx = transactionChain.newReadOnlyTransaction();
\r
161 Optional<VppEndpoint> readVppEp = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, vppEpIid, rTx);
\r
163 if (readVppEp.isPresent()) {
\r
164 writeVppEndpoint(vppEpIid, null);
\r
165 LOG.debug("Deleted vpp-endpoint {}", vppEpKey);
\r
169 private synchronized void writeVppEndpoint(InstanceIdentifier<VppEndpoint> vppEpIid, VppEndpoint vppEp) {
\r
170 WriteTransaction wTx = transactionChain.newWriteOnlyTransaction();
\r
171 if (vppEp != null) {
\r
172 wTx.put(LogicalDatastoreType.CONFIGURATION, vppEpIid, vppEp, true);
\r
174 wTx.delete(LogicalDatastoreType.CONFIGURATION, vppEpIid);
\r
180 VppEndpoint buildVppEndpoint(Port port, BaseEndpointByPort bebp) {
\r
181 PortBindingExtension portBinding = port.getAugmentation(PortBindingExtension.class);
\r
182 VppEndpointBuilder vppEpBuilder = new VppEndpointBuilder().setDescription("neutron port")
\r
183 .setContextId(bebp.getContextId())
\r
184 .setContextType(bebp.getContextType())
\r
185 .setAddress(bebp.getAddress())
\r
186 .setAddressType(bebp.getAddressType())
\r
187 .setVppInterfaceName(VPP_INTERFACE_NAME_PREFIX + bebp.getPortId().getValue())
\r
188 .setVppNodePath(createNodeIid(new NodeId(portBinding.getHostId())));
\r
189 if (port.getDeviceOwner().contains(COMPUTE_OWNER)) {
\r
190 String socket = socketInfo.getSocketPath() + socketInfo.getSocketPrefix() + bebp.getPortId().getValue();
\r
191 vppEpBuilder.setInterfaceTypeChoice(new VhostUserCaseBuilder().setSocket(socket).build());
\r
192 } else if (port.getDeviceOwner().contains(DHCP_OWNER) && port.getMacAddress() != null) {
\r
193 TapCase tapCase = new TapCaseBuilder().setPhysicalAddress(new PhysAddress(port.getMacAddress().getValue()))
\r
194 .setName(createPortName(port.getUuid()))
\r
196 vppEpBuilder.setInterfaceTypeChoice(tapCase);
\r
197 } else if (isValidQRouterPort(port)) {
\r
198 TapCase tapCase = new TapCaseBuilder().setPhysicalAddress(new PhysAddress(port.getMacAddress().getValue()))
\r
199 .setName(createQRouterPortName(port.getUuid()))
\r
201 vppEpBuilder.setInterfaceTypeChoice(tapCase);
\r
202 } else if (isValidVppRouterPort(port)) {
\r
203 vppEpBuilder.setInterfaceTypeChoice(getLoopbackCase(port));
\r
205 return vppEpBuilder.build();
\r
208 private LoopbackCase getLoopbackCase(Port port) {
\r
209 LoopbackCaseBuilder loopbackCase = new LoopbackCaseBuilder()
\r
210 .setPhysAddress(new PhysAddress(port.getMacAddress().getValue()));
\r
211 Optional<FixedIps> fixedIpsOptional = resolveFirstFixedIps(port);
\r
212 if(fixedIpsOptional.isPresent() && fixedIpsOptional.get().getIpAddress() != null){
\r
213 loopbackCase.setIpAddress(fixedIpsOptional.get().getIpAddress());
\r
214 ReadOnlyTransaction rTx = transactionChain.newReadOnlyTransaction();
\r
215 Optional<Subnet> subnetOptional =
\r
216 DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
\r
217 InstanceIdentifier.builder(Neutron.class)
\r
218 .child(Subnets.class)
\r
219 .child(Subnet.class, new SubnetKey(fixedIpsOptional.get().getSubnetId()))
\r
221 if (subnetOptional.isPresent()) {
\r
222 Ipv4Prefix ipv4Prefix = subnetOptional.get().getCidr().getIpv4Prefix();
\r
223 loopbackCase.setIpPrefix(new IpPrefix(ipv4Prefix));
\r
225 LOG.warn("IpPrefix for loopback port: {} was not set.", port);
\r
227 if (loopbackCase.getIpAddress() != null && loopbackCase.getIpPrefix() != null) {
\r
228 loopbackCase.setBvi(true);
\r
229 LOG.trace("Creating loopback BVI interface: {} for VPP router port: {}.", loopbackCase, port);
\r
233 LOG.warn("IpAddress for loopback port: {} was not set.", port);
\r
235 return loopbackCase.build();
\r
239 * If Qrouter (L3 Agent) is in use, any of Openstack neutron routers is not going be mapped
\r
242 private boolean isValidQRouterPort(Port port) {
\r
243 Optional<Router> optRouter = getRouterOptional(port);
\r
244 return !optRouter.isPresent() && port.getDeviceOwner().contains(ROUTER_OWNER)
\r
245 && port.getMacAddress() != null;
\r
248 private boolean isValidVppRouterPort(Port port) {
\r
249 Optional<Router> optRouter = getRouterOptional(port);
\r
250 return optRouter.isPresent() && port.getDeviceOwner().contains(ROUTER_OWNER)
\r
251 && port.getMacAddress() != null;
\r
254 private Optional<Router> getRouterOptional(Port port) {
\r
255 ReadOnlyTransaction rTx = transactionChain.newReadOnlyTransaction();
\r
256 InstanceIdentifier<Router> routerIid = InstanceIdentifier.builder(Neutron.class)
\r
257 .child(Routers.class)
\r
258 .child(Router.class, new RouterKey(new Uuid(port.getDeviceId())))
\r
260 Optional<Router> optRouter = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, routerIid, rTx);
\r
265 public static Optional<FixedIps> resolveFirstFixedIps(Port port) {
\r
266 List<FixedIps> fixedIps = port.getFixedIps();
\r
267 if (fixedIps != null && !fixedIps.isEmpty()) {
\r
268 return Optional.of(fixedIps.get(0));
\r
270 return Optional.absent();
\r
273 private String createPortName(Uuid portUuid) {
\r
274 String tapPortName;
\r
275 String uuid = portUuid.getValue();
\r
276 if (uuid != null && uuid.length() >= 12) {
\r
277 tapPortName = TAP_PORT_NAME_PREFIX + uuid.substring(0, 11);
\r
279 tapPortName = TAP_PORT_NAME_PREFIX + uuid;
\r
281 return tapPortName;
\r
284 private String createQRouterPortName(Uuid portUuid) {
\r
285 String tapPortName;
\r
286 String uuid = portUuid.getValue();
\r
287 if (uuid != null && uuid.length() >= 12) {
\r
288 tapPortName = RT_PORT_NAME_PREFIX + uuid.substring(0, 11);
\r
290 tapPortName = RT_PORT_NAME_PREFIX + uuid;
\r
292 return tapPortName;
\r
295 private InstanceIdentifier<Node> createNodeIid(NodeId nodeId) {
\r
296 return InstanceIdentifier.builder(NetworkTopology.class)
\r
297 .child(Topology.class, new TopologyKey(new TopologyId(NETCONF_TOPOLOGY_ID)))
\r
298 .child(Node.class, new NodeKey(nodeId))
\r
302 private InstanceIdentifier<VppEndpoint> createVppEndpointIid(VppEndpointKey vppEpKey) {
\r
303 return InstanceIdentifier.builder(Config.class).child(VppEndpoint.class, vppEpKey).build();
\r
306 private InstanceIdentifier<BaseEndpointByPort> createBaseEpByPortIid(Uuid uuid) {
\r
307 return createBaseEpByPortIid(new UniqueId(uuid.getValue()));
\r
310 private InstanceIdentifier<BaseEndpointByPort> createBaseEpByPortIid(UniqueId uuid) {
\r
311 return InstanceIdentifier.builder(Mappings.class)
\r
312 .child(GbpByNeutronMappings.class)
\r
313 .child(BaseEndpointsByPorts.class)
\r
314 .child(BaseEndpointByPort.class, new BaseEndpointByPortKey(uuid))
\r
318 InstanceIdentifier<Port> createWildcartedPortIid() {
\r
319 return portsIid().child(Port.class).build();
\r
322 private InstanceIdentifier<Port> createPortIid(UniqueId uuid) {
\r
323 return portsIid().child(Port.class, new PortKey(new Uuid(uuid.getValue()))).build();
\r
326 private InstanceIdentifierBuilder<Ports> portsIid() {
\r
327 return InstanceIdentifier.builder(Neutron.class).child(Ports.class);
\r
331 public void onTransactionChainFailed(TransactionChain<?, ?> chain, AsyncTransaction<?, ?> transaction,
\r
333 LOG.error("Transaction chain failed. {} \nTransaction which caused the chain to fail {}", cause.getMessage(),
\r
334 transaction, cause);
\r
335 transactionChain.close();
\r
336 transactionChain = dataBroker.createTransactionChain(this);
\r
340 public void onTransactionChainSuccessful(TransactionChain<?, ?> chain) {
\r
341 LOG.trace("Transaction chain was successful. {}", chain);
\r