OF port creation and update config side implementation
[genius.git] / itm / itm-impl / src / main / java / org / opendaylight / genius / itm / confighelpers / ItmOfTunnelAddWorker.java
1 /*
2  * Copyright (c) 2020 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.genius.itm.confighelpers;
10
11 import com.google.common.collect.ImmutableMap;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import java.time.Duration;
14 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.HashMap;
17 import java.util.Map;
18 import java.util.Optional;
19 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
20 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
21 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
22 import org.opendaylight.genius.itm.cache.OvsBridgeRefEntryCache;
23 import org.opendaylight.genius.itm.impl.ITMBatchingUtils;
24 import org.opendaylight.genius.itm.itmdirecttunnels.renderer.ovs.utilities.DirectTunnelUtils;
25 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
26 import org.opendaylight.mdsal.binding.api.DataBroker;
27 import org.opendaylight.mdsal.binding.api.WriteTransaction;
28 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
29 import org.opendaylight.mdsal.common.api.ReadFailedException;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlanGpe;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.config.rev160406.ItmConfig;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.OvsBridgeRefInfo;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.ovs.bridge.ref.info.OvsBridgeRefEntry;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.ovs.bridge.ref.info.OvsBridgeRefEntryKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnTepConfig;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnTepConfigBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.tep.config.OfDpnTep;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.tep.config.OfDpnTepKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeBase;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbPortInterfaceAttributes;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentationBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Options;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.OptionsBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.OptionsKey;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.opendaylight.yangtools.yang.common.Uint16;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 public class ItmOfTunnelAddWorker {
56
57     private static final Logger LOG = LoggerFactory.getLogger(ItmOfTunnelAddWorker.class) ;
58     private static final Logger EVENT_LOGGER = LoggerFactory.getLogger("GeniusEventLogger");
59
60     private final DataBroker dataBroker;
61     private final ManagedNewTransactionRunner txRunner;
62     private final JobCoordinator jobCoordinator;
63     private final DirectTunnelUtils directTunnelUtils;
64     private final OvsBridgeRefEntryCache ovsBridgeRefEntryCache;
65     private final DataTreeEventCallbackRegistrar eventCallbacks;
66     private final ItmConfig itmCfg;
67
68     public ItmOfTunnelAddWorker(DataBroker dataBroker, JobCoordinator jobCoordinator, ItmConfig itmCfg,
69                                 DirectTunnelUtils directTunnelUtils, OvsBridgeRefEntryCache ovsBridgeRefEntryCache,
70                                 DataTreeEventCallbackRegistrar eventCallbacks) {
71         this.dataBroker = dataBroker;
72         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
73         this.jobCoordinator = jobCoordinator;
74         this.itmCfg = itmCfg;
75         this.directTunnelUtils = directTunnelUtils;
76         this.ovsBridgeRefEntryCache = ovsBridgeRefEntryCache;
77         this.eventCallbacks = eventCallbacks;
78     }
79
80     public Collection<? extends ListenableFuture<Void>> addOfPort(Map<OfDpnTepKey, OfDpnTep> dpnsTepMap) {
81         return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(transaction -> {
82             for (OfDpnTep dpn : dpnsTepMap.values()) {
83                 buildOfPort(dpn, transaction);
84             }
85             updateOfDpnsConfig(dpnsTepMap, transaction);
86         }));
87     }
88
89     private void updateOfDpnsConfig(Map<OfDpnTepKey, OfDpnTep> dpnsTepMap, WriteTransaction tx) {
90         DpnTepConfigBuilder tepConfigBuilder = new DpnTepConfigBuilder();
91         tepConfigBuilder.setOfDpnTep(dpnsTepMap);
92         InstanceIdentifier<DpnTepConfig> dpnTepsConfII = InstanceIdentifier.builder(DpnTepConfig.class).build();
93         tx.merge(LogicalDatastoreType.CONFIGURATION, dpnTepsConfII, tepConfigBuilder.build());
94     }
95
96     private void buildOfPort(OfDpnTep dpnTep, WriteTransaction transaction) throws ReadFailedException {
97         Optional<OvsBridgeRefEntry> ovsBridgeRefEntry = ovsBridgeRefEntryCache.get(dpnTep.getSourceDpnId());
98         DirectTunnelUtils.createBridgeTunnelEntryInConfigDS(dpnTep.getSourceDpnId(), dpnTep.getOfPortName());
99
100         if (ovsBridgeRefEntry.isPresent()) {
101             LOG.debug("creating bridge interface on dpn {}", dpnTep.getSourceDpnId());
102             InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid =
103                     (InstanceIdentifier<OvsdbBridgeAugmentation>) ovsBridgeRefEntry.get()
104                             .getOvsBridgeReference().getValue();
105             LOG.debug("adding port to the bridge:{} tunnelName: {}", bridgeIid, dpnTep.getOfPortName());
106             addOfPortToBridge(bridgeIid, dpnTep);
107         } else {
108             LOG.debug("Bridge not found. Registering Eventcallback for dpid {}", dpnTep.getSourceDpnId());
109
110             InstanceIdentifier<OvsBridgeRefEntry> bridgeRefEntryFromDS =
111                     InstanceIdentifier.builder(OvsBridgeRefInfo.class)
112                             .child(OvsBridgeRefEntry.class, new OvsBridgeRefEntryKey(dpnTep.getSourceDpnId())).build();
113
114             eventCallbacks.onAdd(LogicalDatastoreType.OPERATIONAL, bridgeRefEntryFromDS, (refEntryIid) -> {
115                 addPortToBridgeOnCallback(dpnTep, refEntryIid);
116                 return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
117             }, Duration.ofMillis(5000), (id) -> {
118                     try {
119                         Optional<OvsBridgeRefEntry> ovsBridgeRefEntryOnCallback =
120                                 ovsBridgeRefEntryCache.get(dpnTep.getSourceDpnId());
121                         InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIidOnCallback =
122                                 (InstanceIdentifier<OvsdbBridgeAugmentation>) ovsBridgeRefEntryOnCallback.get()
123                                         .getOvsBridgeReference().getValue();
124                         addOfPortToBridge(bridgeIidOnCallback, dpnTep);
125                     } catch (ReadFailedException e) {
126                         LOG.error("Bridge not found in DS/cache for dpId {}", dpnTep.getSourceDpnId());
127                     }
128                 });
129         }
130
131     }
132
133     private void addPortToBridgeOnCallback(OfDpnTep dpnTep, OvsBridgeRefEntry bridgeRefEntry) {
134         InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid =
135                 (InstanceIdentifier<OvsdbBridgeAugmentation>) bridgeRefEntry.getOvsBridgeReference().getValue();
136         addOfPortToBridge(bridgeIid, dpnTep);
137     }
138
139     private void addOfPortToBridge(InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid, OfDpnTep dpnTep) {
140         Class<? extends InterfaceTypeBase> type =
141                 DirectTunnelUtils.TUNNEL_TYPE_MAP.get(dpnTep.getTunnelType());
142         if (type == null) {
143             LOG.warn("Unknown Tunnel Type obtained while creating port {} on dpn {}",
144                     dpnTep.getOfPortName(), dpnTep.getSourceDpnId());
145             return;
146         }
147
148         ImmutableMap.Builder<String, String> options = new ImmutableMap.Builder<>();
149
150         // Options common to any kind of tunnel
151         options.put(directTunnelUtils.TUNNEL_OPTIONS_KEY, directTunnelUtils.TUNNEL_OPTIONS_VALUE_FLOW);
152         IpAddress localIp = dpnTep.getTepIp();
153         options.put(DirectTunnelUtils.TUNNEL_OPTIONS_LOCAL_IP, localIp.stringValue());
154         options.put(directTunnelUtils.TUNNEL_OPTIONS_REMOTE_IP, directTunnelUtils.TUNNEL_OPTIONS_VALUE_FLOW);
155         options.put(DirectTunnelUtils.TUNNEL_OPTIONS_TOS, DirectTunnelUtils.TUNNEL_OPTIONS_TOS_VALUE_INHERIT);
156
157         if (TunnelTypeVxlanGpe.class.equals(type)) {
158             options.put(DirectTunnelUtils.TUNNEL_OPTIONS_EXTS, DirectTunnelUtils.TUNNEL_OPTIONS_VALUE_GPE);
159             options.put(DirectTunnelUtils.TUNNEL_OPTIONS_NSI, DirectTunnelUtils.TUNNEL_OPTIONS_VALUE_FLOW);
160             options.put(DirectTunnelUtils.TUNNEL_OPTIONS_NSP, DirectTunnelUtils.TUNNEL_OPTIONS_VALUE_FLOW);
161             options.put(DirectTunnelUtils.TUNNEL_OPTIONS_NSHC1, DirectTunnelUtils.TUNNEL_OPTIONS_VALUE_FLOW);
162             options.put(DirectTunnelUtils.TUNNEL_OPTIONS_NSHC2, DirectTunnelUtils.TUNNEL_OPTIONS_VALUE_FLOW);
163             options.put(DirectTunnelUtils.TUNNEL_OPTIONS_NSHC3, DirectTunnelUtils.TUNNEL_OPTIONS_VALUE_FLOW);
164             options.put(DirectTunnelUtils.TUNNEL_OPTIONS_NSHC4, DirectTunnelUtils.TUNNEL_OPTIONS_VALUE_FLOW);
165             // VxLAN-GPE interfaces will not use the default UDP port to avoid problems with other meshes
166             options.put(DirectTunnelUtils.TUNNEL_OPTIONS_DESTINATION_PORT,
167                     DirectTunnelUtils.TUNNEL_OPTIONS_VALUE_GPE_DESTINATION_PORT);
168         }
169
170         addTerminationPoint(bridgeIid, dpnTep.getOfPortName(), 0, type, options.build());
171     }
172
173     private void addTerminationPoint(InstanceIdentifier<?> bridgeIid, String ofPortName, int vlanId,
174                                      Class<? extends InterfaceTypeBase> type, Map<String, String> options) {
175
176         final InstanceIdentifier<TerminationPoint> tpIid = DirectTunnelUtils.createTerminationPointInstanceIdentifier(
177                 InstanceIdentifier.keyOf(bridgeIid.firstIdentifierOf(
178                         org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang
179                                 .network.topology.rev131021.network.topology.topology.Node.class)), ofPortName);
180         OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder();
181
182         tpAugmentationBuilder.setName(ofPortName);
183
184         if (type != null) {
185             tpAugmentationBuilder.setInterfaceType(type);
186         }
187
188         if (options != null) {
189             Map<OptionsKey, Options> optionsMap = new HashMap<>();
190             for (Map.Entry<String, String> entry : options.entrySet()) {
191                 OptionsBuilder optionsBuilder = new OptionsBuilder();
192                 optionsBuilder.withKey(new OptionsKey(entry.getKey()));
193                 optionsBuilder.setOption(entry.getKey());
194                 optionsBuilder.setValue(entry.getValue());
195                 optionsMap.put(optionsBuilder.key(),optionsBuilder.build());
196             }
197             tpAugmentationBuilder.setOptions(optionsMap);
198         }
199
200         if (vlanId != 0) {
201             tpAugmentationBuilder.setVlanMode(OvsdbPortInterfaceAttributes.VlanMode.Access);
202             tpAugmentationBuilder.setVlanTag(new VlanId(Uint16.valueOf(vlanId)));
203         }
204
205         TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
206         tpBuilder.withKey(InstanceIdentifier.keyOf(tpIid));
207         tpBuilder.addAugmentation(tpAugmentationBuilder.build());
208
209         ITMBatchingUtils.write(tpIid, tpBuilder.build(), ITMBatchingUtils.EntityType.TOPOLOGY_CONFIG);
210     }
211 }