1 package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
3 import static com.google.common.base.Preconditions.checkNotNull;
5 import java.util.ArrayList;
8 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
9 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
10 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
11 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
12 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
13 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.DataStoreHelper;
14 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.IidFactory;
15 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
16 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils.ForwardingCtx;
17 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NeutronUtils;
18 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.Utils;
19 import org.opendaylight.neutron.spi.INeutronPortCRUD;
20 import org.opendaylight.neutron.spi.INeutronRouterAware;
21 import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
22 import org.opendaylight.neutron.spi.NeutronCRUDInterfaces;
23 import org.opendaylight.neutron.spi.NeutronPort;
24 import org.opendaylight.neutron.spi.NeutronRouter;
25 import org.opendaylight.neutron.spi.NeutronRouter_Interface;
26 import org.opendaylight.neutron.spi.NeutronSecurityRule;
27 import org.opendaylight.neutron.spi.NeutronSubnet;
28 import org.opendaylight.neutron.spi.Neutron_IPs;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3Builder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.network.mappings.NetworkMapping;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomain;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomainBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3ContextBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.SubnetBuilder;
49 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
53 import com.google.common.base.Optional;
54 import com.google.common.base.Strings;
55 import com.google.common.collect.ImmutableList;
57 public class NeutronRouterAware implements INeutronRouterAware {
59 private static final Logger LOG = LoggerFactory.getLogger(NeutronRouterAware.class);
60 private static final NeutronRouterAware INSTANCE = new NeutronRouterAware();
61 private static DataBroker dataProvider;
62 private static EndpointService epService;
64 private NeutronRouterAware() {
65 if (NeutronRouterAware.INSTANCE != null) {
66 throw new IllegalStateException("Already instantiated");
70 public static NeutronRouterAware getInstance() {
71 return NeutronRouterAware.INSTANCE;
74 public static void init(DataBroker dataProvider, EndpointService epService) {
75 NeutronRouterAware.dataProvider = checkNotNull(dataProvider);
76 NeutronRouterAware.epService = checkNotNull(epService);
80 public int canCreateRouter(NeutronRouter router) {
81 LOG.trace("canCreateRouter - {}", router);
82 // nothing to consider
87 public void neutronRouterCreated(NeutronRouter router) {
88 LOG.trace("neutronRouterCreated - {}", router);
89 // TODO Li msunal external gateway
93 public int canUpdateRouter(NeutronRouter delta, NeutronRouter original) {
94 LOG.trace("canUpdateRouter - delta: {} original: {}", delta, original);
95 // TODO Li msunal external gateway
100 public void neutronRouterUpdated(NeutronRouter router) {
101 LOG.trace("neutronRouterUpdated - {}", router);
102 // TODO Li msunal external gateway
106 public int canDeleteRouter(NeutronRouter router) {
107 LOG.trace("canDeleteRouter - {}", router);
108 // nothing to consider
109 return StatusCode.OK;
113 public void neutronRouterDeleted(NeutronRouter router) {
114 LOG.trace("neutronRouterDeleted - {}", router);
115 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
116 TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
117 Optional<EndpointGroup> potentialEpg = DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
118 IidFactory.endpointGroupIid(tenantId, MappingUtils.EPG_ROUTER_ID), rwTx);
119 if (!potentialEpg.isPresent()) {
120 LOG.warn("Illegal state - Endpoint group {} does not exist.", MappingUtils.EPG_ROUTER_ID.getValue());
124 DataStoreHelper.submitToDs(rwTx);
128 public int canAttachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
129 LOG.trace("canAttachInterface - router: {} interface: {}", router, routerInterface);
130 try (ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction()) {
131 L3ContextId l3ContextIdFromRouterId = new L3ContextId(router.getID());
132 TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
133 SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
134 Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
135 IidFactory.subnetIid(tenantId, subnetId), rTx);
136 if (!potentialSubnet.isPresent()) {
137 LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
138 return StatusCode.NOT_FOUND;
140 Subnet subnet = potentialSubnet.get();
141 L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
142 ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rTx);
143 if (fwCtx.getL3Context() != null && fwCtx.getL3Context().equals(l3ContextIdFromRouterId)) {
145 LOG.warn("Illegal state - Neutron mapper does not support multiple router interfaces in the same subnet yet.");
146 return StatusCode.FORBIDDEN;
148 return StatusCode.OK;
153 public void neutronRouterInterfaceAttached(NeutronRouter router, NeutronRouter_Interface routerInterface) {
154 LOG.trace("neutronRouterInterfaceAttached - router: {} interface: {}", router, routerInterface);
155 INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);
156 if (portInterface == null) {
157 LOG.warn("Illegal state - No provider for {}", INeutronPortCRUD.class.getName());
161 INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
162 if (subnetInterface == null) {
163 LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
167 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
168 TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
169 L3ContextId l3ContextIdFromRouterId = new L3ContextId(router.getID());
170 InstanceIdentifier<L3Context> l3ContextIidForRouterId = IidFactory.l3ContextIid(tenantId,
171 l3ContextIdFromRouterId);
172 Optional<L3Context> potentialL3ContextForRouter = DataStoreHelper.readFromDs(
173 LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, rwTx);
174 // add L3 context if missing
175 if (!potentialL3ContextForRouter.isPresent()) {
176 Name l3ContextName = null;
177 if (!Strings.isNullOrEmpty(router.getName())) {
178 l3ContextName = new Name(router.getName());
180 L3Context l3Context = new L3ContextBuilder().setId(l3ContextIdFromRouterId)
181 .setName(l3ContextName)
182 .setDescription(new Description(MappingUtils.NEUTRON_ROUTER__ + router.getID()))
184 rwTx.put(LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, l3Context);
187 SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
188 Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
189 IidFactory.subnetIid(tenantId, subnetId), rwTx);
190 if (!potentialSubnet.isPresent()) {
191 LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
196 // Based on Neutron Northbound - Port representing router interface
197 // contains exactly on
199 NeutronPort routerPort = portInterface.getPort(routerInterface.getPortUUID());
200 // TODO: Li alagalah: Add gateways and prefixes instead of
202 Subnet subnet = new SubnetBuilder(potentialSubnet.get()).setVirtualRouterIp(
203 Utils.createIpAddress(routerPort.getFixedIPs().get(0).getIpAddress())).build();
204 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnetId), subnet);
205 if (subnet.getParent() == null) {
206 LOG.warn("Illegal state - subnet {} does not have a parent.", subnetId.getValue());
211 L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
212 ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
213 if (fwCtx.getL2BridgeDomain() == null) {
214 LOG.warn("Illegal state - l2-flood-domain {} does not have a parent.", l2FdId.getValue());
219 L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(
220 l3ContextIdFromRouterId).build();
221 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BridgeDomain.getId()),
224 // create security rules for router
225 List<NeutronSecurityRule> routerSecRules = createRouterSecRules(routerPort, null, rwTx);
226 if (routerSecRules == null) {
230 for (NeutronSecurityRule routerSecRule : routerSecRules) {
231 boolean isRouterSecRuleAdded = NeutronSecurityRuleAware.addNeutronSecurityRule(routerSecRule, rwTx);
232 if (!isRouterSecRuleAdded) {
238 List<L3> l3Eps = new ArrayList<>();
239 L3ContextId oldL3ContextId = fwCtx.getL3Context().getId();
240 NeutronSubnet neutronSubnet = subnetInterface.getSubnet(subnetId.getValue());
241 List<NeutronPort> portsInNeutronSubnet = neutronSubnet.getPortsInSubnet();
242 for (NeutronPort port : portsInNeutronSubnet) {
243 boolean isPortAdded = NeutronPortAware.addNeutronPort(port, rwTx, epService);
248 // TODO Li msunal this has to be rewrite when OFOverlay renderer
249 // will support l3-endpoints.
250 Neutron_IPs firstIp = MappingUtils.getFirstIp(port.getFixedIPs());
251 if (firstIp != null) {
252 l3Eps.add(new L3Builder().setL3Context(oldL3ContextId)
253 .setIpAddress(Utils.createIpAddress(firstIp.getIpAddress()))
258 if (!l3Eps.isEmpty()) {
259 epService.unregisterEndpoint(new UnregisterEndpointInputBuilder().setL3(l3Eps).build());
262 DataStoreHelper.submitToDs(rwTx);
265 public static List<NeutronSecurityRule> createRouterSecRules(NeutronPort port, EndpointGroupId consumerEpgId,
266 ReadTransaction rTx) {
267 TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
268 Neutron_IPs firstIp = MappingUtils.getFirstIp(port.getFixedIPs());
269 if (firstIp == null) {
270 LOG.warn("Illegal state - Router port does not have an IP address.");
273 SubnetId routerSubnetId = new SubnetId(firstIp.getSubnetUUID());
274 Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
275 IidFactory.subnetIid(tenantId, routerSubnetId), rTx);
276 if (!potentialSubnet.isPresent()) {
277 LOG.warn("Illegal state - Subnet {} where is router port does not exist.", routerSubnetId.getValue());
280 IpPrefix ipSubnet = potentialSubnet.get().getIpPrefix();
281 NeutronSecurityRule routerRuleEgress = createRouterSecRule(port.getID(), tenantId, ipSubnet, consumerEpgId,
283 NeutronSecurityRule routerRuleIngress = createRouterSecRule(port.getID(), tenantId, ipSubnet, consumerEpgId,
285 return ImmutableList.of(routerRuleEgress, routerRuleIngress);
288 private static NeutronSecurityRule createRouterSecRule(String ruleUuid, TenantId tenantId, IpPrefix ipSubnet,
289 EndpointGroupId consumerEpgId, boolean isEgress) {
290 NeutronSecurityRule dhcpSecRule = new NeutronSecurityRule();
291 dhcpSecRule.setSecurityRuleGroupID(MappingUtils.EPG_ROUTER_ID.getValue());
292 dhcpSecRule.setSecurityRuleTenantID(tenantId.getValue());
293 dhcpSecRule.setSecurityRuleRemoteIpPrefix(Utils.getStringIpPrefix(ipSubnet));
295 dhcpSecRule.setSecurityRuleUUID(NeutronUtils.EGRESS + "__" + ruleUuid);
296 dhcpSecRule.setSecurityRuleDirection(NeutronUtils.EGRESS);
298 dhcpSecRule.setSecurityRuleUUID(NeutronUtils.INGRESS + "__" + ruleUuid);
299 dhcpSecRule.setSecurityRuleDirection(NeutronUtils.INGRESS);
301 if (ipSubnet.getIpv4Prefix() != null) {
302 dhcpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv4);
304 dhcpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv6);
310 public int canDetachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
311 LOG.trace("canDetachInterface - router: {} interface: {}", router, routerInterface);
312 // nothing to consider
313 return StatusCode.OK;
317 public void neutronRouterInterfaceDetached(NeutronRouter router, NeutronRouter_Interface routerInterface) {
318 LOG.trace("neutronRouterInterfaceDetached - router: {} interface: {}", router, routerInterface);
319 INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
320 if (subnetInterface == null) {
321 LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
325 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
326 TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
327 L3ContextId l3ContextId = new L3ContextId(router.getID());
328 SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
329 InstanceIdentifier<L3Context> l3ContextIid = IidFactory.l3ContextIid(tenantId, l3ContextId);
330 DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
331 IidFactory.l3ContextIid(tenantId, l3ContextId), rwTx);
333 Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
334 IidFactory.subnetIid(tenantId, subnetId), rwTx);
335 if (!potentialSubnet.isPresent()) {
336 LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
341 Subnet subnet = new SubnetBuilder(potentialSubnet.get()).setVirtualRouterIp(null).build();
342 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnetId), subnet);
344 L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
345 ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
346 if (fwCtx.getL2BridgeDomain() == null) {
347 LOG.warn("Illegal state - l2-flood-domain {} does not have a parent.", l2FdId.getValue());
352 Optional<NetworkMapping> potentialNetworkMapping = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
353 IidFactory.networkMappingIid(l2FdId), rwTx);
354 if (!potentialNetworkMapping.isPresent()) {
355 LOG.warn("Illegal state - network-mapping {} does not exist.", l2FdId.getValue());
360 L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(
361 potentialNetworkMapping.get().getL3ContextId()).build();
362 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BridgeDomain.getId()),
365 NeutronSubnet neutronSubnet = subnetInterface.getSubnet(subnetId.getValue());
366 List<NeutronPort> portsInNeutronSubnet = neutronSubnet.getPortsInSubnet();
367 for (NeutronPort port : portsInNeutronSubnet) {
368 boolean isPortAdded = NeutronPortAware.addNeutronPort(port, rwTx, epService);