2 * Copyright (c) 2015 - 2016 HPE 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
8 package org.opendaylight.netvirt.neutronvpn;
10 import java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.List;
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
16 import org.opendaylight.genius.mdsalutil.MDSALUtil;
17 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
18 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
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.IpPrefix;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeRefInfo;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntry;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntryKey;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.TransportZones;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.TransportZonesBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZone;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZoneBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZoneKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.Subnets;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.SubnetsBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.SubnetsKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.Vteps;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.VtepsBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.config.rev160806.NeutronvpnConfig;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVxlan;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.NetworkKey;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.PortKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
54 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
58 public class TransportZoneNotificationUtil {
60 private static final Logger LOG = LoggerFactory.getLogger(TransportZoneNotificationUtil.class);
61 private static final String OF_URI_SEPARATOR = ":";
62 private static final String TUNNEL_PORT = "tunnel_port";
63 private static final String LOCAL_IP = "local_ip";
64 private static final String ALL_SUBNETS = "0.0.0.0/0";
65 private final DataBroker dataBroker;
66 private final NeutronvpnManager nvManager;
67 private final MdsalUtils mdsalUtils;
68 private final SouthboundUtils southBoundUtils;
69 private final NeutronvpnConfig neutronvpnConfig;
71 public TransportZoneNotificationUtil(DataBroker dbx, NeutronvpnManager nvManager) {
72 this.dataBroker = dbx;
73 this.nvManager = nvManager;
74 this.mdsalUtils = new MdsalUtils(dbx);
75 southBoundUtils = new SouthboundUtils(mdsalUtils);
76 this.neutronvpnConfig = nvManager.getNeutronvpnConfig();
81 * Update/add TransportZone for bridheEntryRef change.<br>
82 * for any update on bridge entry we are looking for all the routers which are affected and try to recreate
84 * @param entry - the BridgeEntryRef that was updated
86 public void updateTrasportZone(BridgeRefEntry entry) {
87 BigInteger dpid = entry.getDpid();
88 Set<RouterDpnList> allRouterDpnList = NeutronvpnUtils.getAllRouterDpnList(dataBroker, dpid);
89 for (RouterDpnList routerDpnList : allRouterDpnList) {
90 updateTrasportZone(routerDpnList);
95 * Update/add TransportZone for interface State inter.<br>
96 * If Transport zone for given Network doesn't exist, then it will be added.<br>
97 * If the TEP of the port's node exists in the TZ, it will not be added.
98 * @param inter - the interface to update
100 // TODO Clean up the exception handling
101 @SuppressWarnings("checkstyle:IllegalCatch")
102 public void updateTrasportZone(Interface inter) {
103 List<Port> ports = getPortsFromInterface(inter);
104 //supports VPN aware VMs (multiple ports for one interface)
105 for (Port port : ports) {
108 if (!checkIfVxlanNetwork(port)) {
112 String subnetIp = ALL_SUBNETS;
114 BigInteger dpnId = getDpnIdFromInterfaceState(inter);
116 InstanceIdentifier<TransportZone> inst = InstanceIdentifier.create(TransportZones.class)
117 .child(TransportZone.class, new TransportZoneKey(port.getNetworkId().getValue()));
118 TransportZone zone = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, inst);
121 zone = createZone(subnetIp, port.getNetworkId().getValue());
124 if (addVtep(zone, subnetIp, dpnId) > 0) {
125 addTransportZone(zone, inter.getName());
128 } catch (Exception e) {
129 LOG.warn("failed to add tunnels on interface added to subnet {}. ", inter, e);
134 // TODO Clean up the exception handling
135 @SuppressWarnings("checkstyle:IllegalCatch")
136 public void updateTrasportZone(RouterDpnList routerDpnList) {
138 InstanceIdentifier<TransportZone> inst = InstanceIdentifier.create(TransportZones.class)
139 .child(TransportZone.class, new TransportZoneKey(routerDpnList.getRouterId()));
140 TransportZone zone = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, inst);
142 String subnetIp = ALL_SUBNETS;
145 for (DpnVpninterfacesList dpnVpninterfacesList : routerDpnList.getDpnVpninterfacesList()) {
146 for (RouterInterfaces routerInterfaces: dpnVpninterfacesList.getRouterInterfaces()) {
147 Uuid portUid = new Uuid(routerInterfaces.getInterface());
148 Port neutronPort = NeutronvpnUtils.getNeutronPort(dataBroker, portUid);
149 if (neutronPort != null) {
150 if (!checkIfVxlanNetwork(neutronPort)) {
154 zone = createZone(subnetIp, routerDpnList.getRouterId());
156 BigInteger dpnId = dpnVpninterfacesList.getDpnId();
157 addedTeps += addVtep(zone, subnetIp, dpnId);
163 addTransportZone(zone, "router " + routerDpnList.getRouterId());
165 } catch (Exception e) {
166 LOG.warn("failed to add tunnels on router added of routerDpnList {}. ", routerDpnList, e);
170 public boolean isAutoTunnelConfigEnabled() {
171 Boolean useTZ = true;
172 if (neutronvpnConfig != null && neutronvpnConfig.isUseTransportZone() != null) {
173 useTZ = neutronvpnConfig.isUseTransportZone();
175 LOG.info("isAutoTunnelConfigEnabled: useTz: {}, neutronvpnConfig: {}", useTZ, neutronvpnConfig);
179 private boolean checkIfVxlanNetwork(Port port) {
180 InstanceIdentifier<Network> networkPath = InstanceIdentifier.create(Neutron.class)
181 .child(Networks.class).child(Network.class, new NetworkKey(port.getNetworkId()));
182 Network network = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, networkPath);
184 if (network == null || !NeutronvpnUtils.isNetworkOfType(network, NetworkTypeVxlan.class)) {
185 LOG.debug("port in non-VXLAN network " + port.getName());
193 private BigInteger getDpnIdFromInterfaceState(Interface inter) {
194 String lowerLayerIf = inter.getLowerLayerIf().get(0);
195 NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
196 BigInteger dpId = new BigInteger(getDpnFromNodeConnectorId(nodeConnectorId));
201 * takes all Neutron Ports that are related to the given interface state
202 * @param interfaceState - interface state to update
203 * @return - list of ports bound to interface
205 private List<Port> getPortsFromInterface(Interface interfaceState) {
206 String physPortId = getPortFromInterfaceName(interfaceState.getName());
207 List<Port> portsList = new ArrayList<>();
209 InstanceIdentifier<Interfaces> interPath = InstanceIdentifier.create(Interfaces.class);
210 Interfaces interfaces = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, interPath);
211 if (interfaces == null) {
212 LOG.error("No interfaces in configuration");
215 List<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
216 .Interface> inters = interfaces.getInterface();
218 // take all interfaces with parent-interface with physPortId name
219 for (org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
220 .Interface inter : inters) {
221 ParentRefs parent = inter.getAugmentation(ParentRefs.class);
222 if (parent == null || !physPortId.equals(parent.getParentInterface())) {
225 String parentInt = inter.getName();
226 Uuid portUid = new Uuid(parentInt);
227 InstanceIdentifier<Port> pathPort = InstanceIdentifier.create(Neutron.class).child(Ports.class)
228 .child(Port.class, new PortKey(portUid));
229 Port port = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, pathPort);
232 LOG.debug("got Interface State of non NeutronPort instance " + physPortId);
243 private String getPortFromInterfaceName(String name) {
244 String[] splitedStr = name.split(OF_URI_SEPARATOR);
245 name = splitedStr.length > 1 ? splitedStr[1] : name;
250 // TODO: code is used in another places. Should be extracted into utility
251 private String getDpnFromNodeConnectorId(NodeConnectorId portId) {
252 String[] split = portId.getValue().split(OF_URI_SEPARATOR);
258 private TransportZone createZone(String subnetIp, String zoneName) {
259 TransportZoneBuilder tzb = new TransportZoneBuilder();
260 tzb.setKey(new TransportZoneKey(zoneName));
261 tzb.setTunnelType(TunnelTypeVxlan.class);
262 tzb.setZoneName(zoneName);
263 List<Subnets> subnets = new ArrayList<>();
264 subnets.add(newSubnets(subnetIp));
265 tzb.setSubnets(subnets);
270 private void addTransportZone(TransportZone zone, String interName) {
271 InstanceIdentifier<TransportZones> path = InstanceIdentifier.builder(TransportZones.class).build();
272 TransportZones zones = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
274 List<TransportZone> zoneList = new ArrayList<>();
276 zones = new TransportZonesBuilder().setTransportZone(zoneList).build();
278 zones.getTransportZone().add(zone);
281 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, path, zones);
282 LOG.info("updating transport zone {} due to {} handling", zone.getZoneName(), interName);
285 private int addVtep(TransportZone zone, String subnetIp, BigInteger dpnId) throws Exception {
287 Subnets subnets = findSubnets(zone.getSubnets(), subnetIp);
289 for (Vteps existingVtep : subnets.getVteps()) {
290 if (existingVtep.getDpnId().equals(dpnId)) {
295 IpAddress nodeIp = getNodeIP(dpnId);
297 VtepsBuilder vtepsBuilder = new VtepsBuilder();
298 vtepsBuilder.setDpnId(dpnId);
299 vtepsBuilder.setIpAddress(nodeIp);
300 vtepsBuilder.setPortname(TUNNEL_PORT);
302 subnets.getVteps().add(vtepsBuilder.build());
307 // search for relevant subnets for the given subnetIP, add one if it is necessary
308 private Subnets findSubnets(List<Subnets> subnets, String subnetIp) {
309 for (Subnets subnet : subnets) {
310 IpPrefix subnetPrefix = new IpPrefix(subnetIp.toCharArray());
311 if (subnet.getPrefix().equals(subnetPrefix)) {
316 Subnets retSubnet = newSubnets(subnetIp);
317 subnets.add(retSubnet);
322 private Subnets newSubnets(String subnetIp) {
323 SubnetsBuilder subnetsBuilder = new SubnetsBuilder();
324 subnetsBuilder.setDeviceVteps(new ArrayList<>());
325 subnetsBuilder.setGatewayIp(new IpAddress("0.0.0.0".toCharArray()));
326 subnetsBuilder.setKey(new SubnetsKey(new IpPrefix(subnetIp.toCharArray())));
327 subnetsBuilder.setVlanId(0);
328 subnetsBuilder.setVteps(new ArrayList<Vteps>());
329 return subnetsBuilder.build();
332 private IpAddress getNodeIP(BigInteger dpId) throws Exception {
333 Node node = getPortsNode(dpId);
334 String localIp = southBoundUtils.getOpenvswitchOtherConfig(node, LOCAL_IP);
335 if (localIp == null) {
336 throw new Exception("missing local_ip key in ovsdb:openvswitch-other-configs in operational"
337 + " network-topology for node: " + node.getNodeId().getValue());
340 return new IpAddress(localIp.toCharArray());
343 @SuppressWarnings("unchecked")
344 private Node getPortsNode(BigInteger dpnId) throws Exception {
345 InstanceIdentifier<BridgeRefEntry> bridgeRefInfoPath =
346 InstanceIdentifier.create(BridgeRefInfo.class).child(BridgeRefEntry.class, new BridgeRefEntryKey(dpnId));
347 BridgeRefEntry bridgeRefEntry = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, bridgeRefInfoPath);
348 if (bridgeRefEntry == null) {
349 throw new Exception("no bridge ref entry found for dpnId: " + dpnId);
352 InstanceIdentifier<Node> nodeId = ((InstanceIdentifier<OvsdbBridgeAugmentation>) bridgeRefEntry
353 .getBridgeReference().getValue()).firstIdentifierOf(Node.class);
354 Node node = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, nodeId);
357 throw new Exception("missing node for dpnId: " + dpnId);