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.neutronvpn.config.rev160806.NeutronvpnConfig;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
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.port.attributes.FixedIps;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.PortKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
59 public class TransportZoneNotificationUtil {
61 private static final Logger LOG = LoggerFactory.getLogger(TransportZoneNotificationUtil.class);
62 private static final String OF_URI_SEPARATOR = ":";
63 private static final String TUNNEL_PORT = "tunnel_port";
64 private static final String LOCAL_IP = "local_ip";
65 private static final String ALL_SUBNETS = "0.0.0.0/0";
66 private final DataBroker dataBroker;
67 private final NeutronvpnManager nvManager;
68 private final MdsalUtils mdsalUtils;
69 private final SouthboundUtils southBoundUtils;
70 private final NeutronvpnConfig neutronvpnConfig;
72 public TransportZoneNotificationUtil(DataBroker dbx, NeutronvpnManager nvManager) {
73 this.dataBroker = dbx;
74 this.nvManager = nvManager;
75 this.mdsalUtils = new MdsalUtils(dbx);
76 southBoundUtils = new SouthboundUtils(mdsalUtils);
77 this.neutronvpnConfig = nvManager.getNeutronvpnConfig();
82 * Update/add TransportZone for bridheEntryRef change.<br>
83 * for any update on bridge entry we are looking for all the routers which are affected and try to recreate
85 * @param entry - the BridgeEntryRef that was updated
87 public void updateTrasportZone(BridgeRefEntry entry) {
88 BigInteger dpid = entry.getDpid();
89 Set<RouterDpnList> allRouterDpnList = NeutronvpnUtils.getAllRouterDpnList(dataBroker, dpid);
90 for (RouterDpnList routerDpnList : allRouterDpnList) {
91 updateTrasportZone(routerDpnList);
96 * Update/add TransportZone for interface State inter.<br>
97 * If Transport zone for given Network doesn't exist, then it will be added.<br>
98 * If the TEP of the port's node exists in the TZ, it will not be added.
99 * @param inter - the interface to update
101 public void updateTrasportZone(Interface inter) {
102 List<Port> ports = getPortsFromInterface(inter);
103 //supports VPN aware VMs (multiple ports for one interface)
104 for (Port port : ports) {
107 if (!checkIfVxlanNetwork(port)) {
111 String subnetIp = ALL_SUBNETS;
113 BigInteger dpnId = getDpnIdFromInterfaceState(inter);
115 InstanceIdentifier<TransportZone> inst = InstanceIdentifier.create(TransportZones.class)
116 .child(TransportZone.class, new TransportZoneKey(port.getNetworkId().getValue()));
117 TransportZone zone = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, inst);
120 zone = createZone(subnetIp, port.getNetworkId().getValue());
123 if (addVtep(zone, subnetIp, dpnId) > 0) {
124 addTransportZone(zone, inter.getName());
127 } catch (Exception e) {
128 LOG.warn("failed to add tunnels on interface added to subnet {}. ", inter, e);
133 public void updateTrasportZone(RouterDpnList routerDpnList) {
135 InstanceIdentifier<TransportZone> inst = InstanceIdentifier.create(TransportZones.class).
136 child(TransportZone.class, new TransportZoneKey(routerDpnList.getRouterId()));
137 TransportZone zone = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, inst);
139 String subnetIp = ALL_SUBNETS;
142 zone = createZone(subnetIp, routerDpnList.getRouterId());
145 for (DpnVpninterfacesList dpnVpninterfacesList : routerDpnList.getDpnVpninterfacesList()) {
146 BigInteger dpnId = dpnVpninterfacesList.getDpnId();
147 addedTeps += addVtep(zone, subnetIp, dpnId);
150 addTransportZone(zone, "router " + routerDpnList.getRouterId());
152 } catch (Exception e) {
153 LOG.warn("failed to add tunnels on router added of routerDpnList {}. ", routerDpnList, e);
157 public boolean isAutoTunnelConfigEnabled() {
158 Boolean useTZ = true;
159 if (neutronvpnConfig != null && neutronvpnConfig.isUseTransportZone() != null) {
160 useTZ = neutronvpnConfig.isUseTransportZone();
162 LOG.info("isAutoTunnelConfigEnabled: useTz: {}, neutronvpnConfig: {}", useTZ, neutronvpnConfig);
166 private boolean checkIfVxlanNetwork(Port port) {
167 InstanceIdentifier<Network> networkPath = InstanceIdentifier.create(Neutron.class)
168 .child(Networks.class).child(Network.class, new NetworkKey(port.getNetworkId()));
169 Network network = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, networkPath);
171 if (network == null || !NeutronvpnUtils.isNetworkOfType(network, NetworkTypeVxlan.class)) {
172 LOG.debug("port in non-VXLAN network " + port.getName());
180 private BigInteger getDpnIdFromInterfaceState(Interface inter) {
181 String lowerLayerIf = inter.getLowerLayerIf().get(0);
182 NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
183 BigInteger dpId = new BigInteger(getDpnFromNodeConnectorId(nodeConnectorId));
188 * takes all Neutron Ports that are related to the given interface state
189 * @param interfaceState - interface state to update
190 * @return - list of ports bound to interface
192 private List<Port> getPortsFromInterface(Interface interfaceState) {
193 String physPortId = getPortFromInterfaceName(interfaceState.getName());
194 List<Port> portsList = new ArrayList<>();
196 InstanceIdentifier<Interfaces> interPath = InstanceIdentifier.create(Interfaces.class);
197 Interfaces interfaces = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, interPath);
198 if (interfaces == null) {
199 LOG.error("No interfaces in configuration");
202 List<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
203 .Interface> inters = interfaces.getInterface();
205 // take all interfaces with parent-interface with physPortId name
206 for (org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
207 .Interface inter : inters) {
208 ParentRefs parent = inter.getAugmentation(ParentRefs.class);
209 if (parent == null || !physPortId.equals(parent.getParentInterface())) {
212 String parentInt = inter.getName();
213 Uuid portUid = new Uuid(parentInt);
214 InstanceIdentifier<Port> pathPort = InstanceIdentifier.create(Neutron.class).child(Ports.class)
215 .child(Port.class, new PortKey(portUid));
216 Port port = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, pathPort);
219 LOG.debug("got Interface State of non NeutronPort instance " + physPortId);
230 private String getPortFromInterfaceName(String name) {
231 String[] splitedStr = name.split(OF_URI_SEPARATOR);
232 name = splitedStr.length > 1 ? splitedStr[1] : name;
237 // TODO: code is used in another places. Should be extracted into utility
238 private String getDpnFromNodeConnectorId(NodeConnectorId portId) {
239 String[] split = portId.getValue().split(OF_URI_SEPARATOR);
245 private TransportZone createZone(String subnetIp, String zoneName) {
246 TransportZoneBuilder tzb = new TransportZoneBuilder();
247 tzb.setKey(new TransportZoneKey(zoneName));
248 tzb.setTunnelType(TunnelTypeVxlan.class);
249 tzb.setZoneName(zoneName);
250 List<Subnets> subnets = new ArrayList<>();
251 subnets.add(newSubnets(subnetIp));
252 tzb.setSubnets(subnets);
257 private void addTransportZone(TransportZone zone, String interName) {
258 InstanceIdentifier<TransportZones> path = InstanceIdentifier.builder(TransportZones.class).build();
259 TransportZones zones = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
261 List<TransportZone> zoneList = new ArrayList<>();
263 zones = new TransportZonesBuilder().setTransportZone(zoneList).build();
265 zones.getTransportZone().add(zone);
268 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, path, zones);
269 LOG.info("updating transport zone {} due to {} handling", zone.getZoneName(), interName);
272 private int addVtep(TransportZone zone, String subnetIp, BigInteger dpnId) throws Exception {
274 Subnets subnets = findSubnets(zone.getSubnets(), subnetIp);
276 for(Vteps existingVtep : subnets.getVteps()){
277 if (existingVtep.getDpnId().equals(dpnId)) {
282 IpAddress nodeIp = getNodeIP(dpnId);
284 VtepsBuilder vtepsBuilder = new VtepsBuilder();
285 vtepsBuilder.setDpnId(dpnId);
286 vtepsBuilder.setIpAddress(nodeIp);
287 vtepsBuilder.setPortname(TUNNEL_PORT);
289 subnets.getVteps().add(vtepsBuilder.build());
294 // search for relevant subnets for the given subnetIP, add one if it is necessary
295 private Subnets findSubnets(List<Subnets> subnets, String subnetIp) {
296 for (Subnets subnet : subnets) {
297 IpPrefix subnetPrefix = new IpPrefix(subnetIp.toCharArray());
298 if (subnet.getPrefix().equals(subnetPrefix)) {
303 Subnets retSubnet = newSubnets(subnetIp);
304 subnets.add(retSubnet);
309 private Subnets newSubnets(String subnetIp) {
310 SubnetsBuilder subnetsBuilder = new SubnetsBuilder();
311 subnetsBuilder.setDeviceVteps(new ArrayList<>());
312 subnetsBuilder.setGatewayIp(new IpAddress("0.0.0.0".toCharArray()));
313 subnetsBuilder.setKey(new SubnetsKey(new IpPrefix(subnetIp.toCharArray())));
314 subnetsBuilder.setVlanId(0);
315 subnetsBuilder.setVteps(new ArrayList<Vteps>());
316 return subnetsBuilder.build();
319 private IpAddress getNodeIP(BigInteger dpId) throws Exception {
320 Node node = getPortsNode(dpId);
321 String localIp = southBoundUtils.getOpenvswitchOtherConfig(node, LOCAL_IP);
322 if (localIp == null) {
323 throw new Exception("missing local_ip key in ovsdb:openvswitch-other-configs in operational"
324 + " network-topology for node: " + node.getNodeId().getValue());
327 return new IpAddress(localIp.toCharArray());
330 @SuppressWarnings("unchecked")
331 private Node getPortsNode(BigInteger dpnId) throws Exception{
332 InstanceIdentifier<BridgeRefEntry> bridgeRefInfoPath = InstanceIdentifier.
333 create(BridgeRefInfo.class).child(BridgeRefEntry.class, new BridgeRefEntryKey(dpnId));
334 BridgeRefEntry bridgeRefEntry = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, bridgeRefInfoPath);
335 if (bridgeRefEntry == null) {
336 throw new Exception("no bridge ref entry found for dpnId: " + dpnId);
339 InstanceIdentifier<Node> nodeId = ((InstanceIdentifier<OvsdbBridgeAugmentation>) bridgeRefEntry
340 .getBridgeReference().getValue()).firstIdentifierOf(Node.class);
341 Node node = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, nodeId);
344 throw new Exception("missing node for dpnId: " + dpnId);