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.InterfacesState;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.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.Network;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
49 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
53 public class TransportZoneNotificationUtil {
55 private static final Logger LOG = LoggerFactory.getLogger(TransportZoneNotificationUtil.class);
56 private static final String OF_URI_SEPARATOR = ":";
57 private static final String TUNNEL_PORT = "tunnel_port";
58 private static final String LOCAL_IP = "local_ip";
59 private static final String ALL_SUBNETS = "0.0.0.0/0";
60 private final DataBroker dataBroker;
61 private final NeutronvpnManager nvManager;
62 private final MdsalUtils mdsalUtils;
63 private final SouthboundUtils southBoundUtils;
64 private final NeutronvpnConfig neutronvpnConfig;
66 public TransportZoneNotificationUtil(DataBroker dbx, NeutronvpnManager nvManager) {
67 this.dataBroker = dbx;
68 this.nvManager = nvManager;
69 this.mdsalUtils = new MdsalUtils(dbx);
70 southBoundUtils = new SouthboundUtils(mdsalUtils);
71 this.neutronvpnConfig = nvManager.getNeutronvpnConfig();
76 * Update/add TransportZone for bridheEntryRef change.<br>
77 * for any update on bridge entry we are looking for all the routers which are affected and try to recreate
79 * @param entry - the BridgeEntryRef that was updated
81 public void updateTransportZone(BridgeRefEntry entry) {
82 BigInteger dpid = entry.getDpid();
83 Set<RouterDpnList> allRouterDpnList = NeutronvpnUtils.getAllRouterDpnList(dataBroker, dpid);
84 for (RouterDpnList routerDpnList : allRouterDpnList) {
85 updateTransportZone(routerDpnList);
90 * Update/add TransportZone for interface config.
91 * If Transport zone for given Network doesn't exist, then it will be added.
92 * If the TEP of the port's node exists in the TZ, it will not be added.
93 * @param iface - the interface to update
95 // TODO Clean up the exception handling
96 @SuppressWarnings("checkstyle:IllegalCatch")
97 public void updateTransportZone(Interface iface) {
99 Uuid portUid = new Uuid(iface.getName());
100 Port port = NeutronvpnUtils.getNeutronPort(dataBroker, portUid);
102 LOG.debug("No neutron port found for iface {} portUuid {}, skipping update of transport zone",
103 portUid, iface.getName());
106 if (!checkIfVxlanNetwork(port)) {
110 String subnetIp = ALL_SUBNETS;
112 ParentRefs parentRefs = iface.getAugmentation(ParentRefs.class);
113 if (parentRefs == null || parentRefs.getParentInterface() == null) {
114 // If parentRefs are missing, try to find a matching parent and update - this will trigger another DCN
115 LOG.debug("parentRef is missing for interface {}, skipping update of transport zone");
119 // FIXME Use IInterfaceManager getInterfaceInfoFromConfigDataStore when refactoring into ELAN
120 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
121 .Interface ifState = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
122 buildStateInterfaceId(parentRefs.getParentInterface()));
124 if (ifState == null) {
125 LOG.debug("ifState is missing for parentRef {} of interface {}, skipping update of transport zone",
126 parentRefs.getParentInterface(), iface.getName());
130 BigInteger dpnId = getDpnIdFromInterfaceState(ifState);
133 InstanceIdentifier<TransportZone> inst = InstanceIdentifier.create(TransportZones.class)
134 .child(TransportZone.class, new TransportZoneKey(port.getNetworkId().getValue()));
135 TransportZone zone = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, inst);
138 zone = createZone(subnetIp, port.getNetworkId().getValue());
141 if (addVtep(zone, subnetIp, dpnId) > 0) {
142 addTransportZone(zone, iface.getName());
145 } catch (Exception e) {
146 LOG.warn("failed to add tunnels on interface added to subnet {}. ", iface, e);
150 // TODO Clean up the exception handling
151 @SuppressWarnings("checkstyle:IllegalCatch")
152 public void updateTransportZone(RouterDpnList routerDpnList) {
154 InstanceIdentifier<TransportZone> inst = InstanceIdentifier.create(TransportZones.class)
155 .child(TransportZone.class, new TransportZoneKey(routerDpnList.getRouterId()));
156 TransportZone zone = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, inst);
158 String subnetIp = ALL_SUBNETS;
161 for (DpnVpninterfacesList dpnVpninterfacesList : routerDpnList.getDpnVpninterfacesList()) {
162 for (RouterInterfaces routerInterfaces: dpnVpninterfacesList.getRouterInterfaces()) {
163 Uuid portUid = new Uuid(routerInterfaces.getInterface());
164 Port neutronPort = NeutronvpnUtils.getNeutronPort(dataBroker, portUid);
165 if (neutronPort != null) {
166 if (!checkIfVxlanNetwork(neutronPort)) {
170 zone = createZone(subnetIp, routerDpnList.getRouterId());
172 BigInteger dpnId = dpnVpninterfacesList.getDpnId();
173 addedTeps += addVtep(zone, subnetIp, dpnId);
179 addTransportZone(zone, "router " + routerDpnList.getRouterId());
181 } catch (Exception e) {
182 LOG.warn("failed to add tunnels on router added of routerDpnList {}. ", routerDpnList, e);
186 public boolean isAutoTunnelConfigEnabled() {
187 Boolean useTZ = true;
188 if (neutronvpnConfig != null && neutronvpnConfig.isUseTransportZone() != null) {
189 useTZ = neutronvpnConfig.isUseTransportZone();
191 LOG.info("isAutoTunnelConfigEnabled: useTz: {}, neutronvpnConfig: {}", useTZ, neutronvpnConfig);
195 private boolean checkIfVxlanNetwork(Port port) {
196 Network network = NeutronvpnUtils.getNeutronNetwork(dataBroker, port.getNetworkId());
197 if (network == null || !NeutronvpnUtils.isNetworkOfType(network, NetworkTypeVxlan.class)) {
198 LOG.debug("port in non-VXLAN network " + port.getName());
206 private BigInteger getDpnIdFromInterfaceState(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
207 .interfaces.rev140508.interfaces.state.Interface ifState) {
208 String lowerLayerIf = ifState.getLowerLayerIf().get(0);
209 NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
210 BigInteger dpId = new BigInteger(getDpnFromNodeConnectorId(nodeConnectorId));
214 // TODO: code is used in another places. Should be extracted into utility
215 private String getDpnFromNodeConnectorId(NodeConnectorId portId) {
216 String[] split = portId.getValue().split(OF_URI_SEPARATOR);
222 private TransportZone createZone(String subnetIp, String zoneName) {
223 TransportZoneBuilder tzb = new TransportZoneBuilder();
224 tzb.setKey(new TransportZoneKey(zoneName));
225 tzb.setTunnelType(TunnelTypeVxlan.class);
226 tzb.setZoneName(zoneName);
227 List<Subnets> subnets = new ArrayList<>();
228 subnets.add(newSubnets(subnetIp));
229 tzb.setSubnets(subnets);
234 private void addTransportZone(TransportZone zone, String interName) {
235 InstanceIdentifier<TransportZones> path = InstanceIdentifier.builder(TransportZones.class).build();
236 TransportZones zones = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
238 List<TransportZone> zoneList = new ArrayList<>();
240 zones = new TransportZonesBuilder().setTransportZone(zoneList).build();
242 zones.getTransportZone().add(zone);
245 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, path, zones);
246 LOG.info("updating transport zone {} due to {} handling", zone.getZoneName(), interName);
249 private int addVtep(TransportZone zone, String subnetIp, BigInteger dpnId) throws Exception {
251 Subnets subnets = findSubnets(zone.getSubnets(), subnetIp);
253 for (Vteps existingVtep : subnets.getVteps()) {
254 if (existingVtep.getDpnId().equals(dpnId)) {
259 IpAddress nodeIp = getNodeIP(dpnId);
261 VtepsBuilder vtepsBuilder = new VtepsBuilder();
262 vtepsBuilder.setDpnId(dpnId);
263 vtepsBuilder.setIpAddress(nodeIp);
264 vtepsBuilder.setPortname(TUNNEL_PORT);
265 vtepsBuilder.setOptionOfTunnel(neutronvpnConfig.isUseOfTunnels());
267 subnets.getVteps().add(vtepsBuilder.build());
272 // search for relevant subnets for the given subnetIP, add one if it is necessary
273 private Subnets findSubnets(List<Subnets> subnets, String subnetIp) {
274 for (Subnets subnet : subnets) {
275 IpPrefix subnetPrefix = new IpPrefix(subnetIp.toCharArray());
276 if (subnet.getPrefix().equals(subnetPrefix)) {
281 Subnets retSubnet = newSubnets(subnetIp);
282 subnets.add(retSubnet);
287 private Subnets newSubnets(String subnetIp) {
288 SubnetsBuilder subnetsBuilder = new SubnetsBuilder();
289 subnetsBuilder.setDeviceVteps(new ArrayList<>());
290 subnetsBuilder.setGatewayIp(new IpAddress("0.0.0.0".toCharArray()));
291 subnetsBuilder.setKey(new SubnetsKey(new IpPrefix(subnetIp.toCharArray())));
292 subnetsBuilder.setVlanId(0);
293 subnetsBuilder.setVteps(new ArrayList<>());
294 return subnetsBuilder.build();
297 private IpAddress getNodeIP(BigInteger dpId) throws Exception {
298 Node node = getPortsNode(dpId);
299 String localIp = southBoundUtils.getOpenvswitchOtherConfig(node, LOCAL_IP);
300 if (localIp == null) {
301 throw new Exception("missing local_ip key in ovsdb:openvswitch-other-configs in operational"
302 + " network-topology for node: " + node.getNodeId().getValue());
305 return new IpAddress(localIp.toCharArray());
308 @SuppressWarnings("unchecked")
309 private Node getPortsNode(BigInteger dpnId) throws Exception {
310 InstanceIdentifier<BridgeRefEntry> bridgeRefInfoPath =
311 InstanceIdentifier.create(BridgeRefInfo.class).child(BridgeRefEntry.class, new BridgeRefEntryKey(dpnId));
312 BridgeRefEntry bridgeRefEntry = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, bridgeRefInfoPath);
313 if (bridgeRefEntry == null) {
314 throw new Exception("no bridge ref entry found for dpnId: " + dpnId);
317 InstanceIdentifier<Node> nodeId = ((InstanceIdentifier<OvsdbBridgeAugmentation>) bridgeRefEntry
318 .getBridgeReference().getValue()).firstIdentifierOf(Node.class);
319 Node node = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, nodeId);
322 throw new Exception("missing node for dpnId: " + dpnId);
328 // FIXME Remove this, duplicated from IfmUtil
329 public static final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces
330 .rev140508.interfaces.state.Interface> buildStateInterfaceId(String interfaceName) {
331 InstanceIdentifier.InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
332 .interfaces.rev140508.interfaces.state.Interface> idBuilder =
333 InstanceIdentifier.builder(InterfacesState.class)
334 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces
335 .rev140508.interfaces.state.Interface.class,
336 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces
337 .rev140508.interfaces.state.InterfaceKey(interfaceName));
338 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces
339 .rev140508.interfaces.state.Interface> id = idBuilder.build();