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 contains exactly on
198 NeutronPort routerPort = portInterface.getPort(routerInterface.getPortUUID());
199 Subnet subnet = new SubnetBuilder(potentialSubnet.get()).setVirtualRouterIp(
200 Utils.createIpAddress(routerPort.getFixedIPs().get(0).getIpAddress())).build();
201 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnetId), subnet);
202 if (subnet.getParent() == null) {
203 LOG.warn("Illegal state - subnet {} does not have a parent.", subnetId.getValue());
208 L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
209 ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
210 if (fwCtx.getL2BridgeDomain() == null) {
211 LOG.warn("Illegal state - l2-flood-domain {} does not have a parent.", l2FdId.getValue());
216 L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(
217 l3ContextIdFromRouterId).build();
218 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BridgeDomain.getId()),
221 // create security rules for router
222 List<NeutronSecurityRule> routerSecRules = createRouterSecRules(routerPort, null, rwTx);
223 if (routerSecRules == null) {
227 for (NeutronSecurityRule routerSecRule : routerSecRules) {
228 boolean isRouterSecRuleAdded = NeutronSecurityRuleAware.addNeutronSecurityRule(routerSecRule, rwTx);
229 if (!isRouterSecRuleAdded) {
235 List<L3> l3Eps = new ArrayList<>();
236 L3ContextId oldL3ContextId = fwCtx.getL3Context().getId();
237 NeutronSubnet neutronSubnet = subnetInterface.getSubnet(subnetId.getValue());
238 List<NeutronPort> portsInNeutronSubnet = neutronSubnet.getPortsInSubnet();
239 for (NeutronPort port : portsInNeutronSubnet) {
240 boolean isPortAdded = NeutronPortAware.addNeutronPort(port, rwTx, epService);
245 // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
246 Neutron_IPs firstIp = MappingUtils.getFirstIp(port.getFixedIPs());
247 if (firstIp != null) {
248 l3Eps.add(new L3Builder().setL3Context(oldL3ContextId)
249 .setIpAddress(Utils.createIpAddress(firstIp.getIpAddress()))
254 if (!l3Eps.isEmpty()) {
255 epService.unregisterEndpoint(new UnregisterEndpointInputBuilder().setL3(l3Eps).build());
258 DataStoreHelper.submitToDs(rwTx);
261 public static List<NeutronSecurityRule> createRouterSecRules(NeutronPort port, EndpointGroupId consumerEpgId,
262 ReadTransaction rTx) {
263 TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
264 Neutron_IPs firstIp = MappingUtils.getFirstIp(port.getFixedIPs());
265 if (firstIp == null) {
266 LOG.warn("Illegal state - Router port does not have an IP address.");
269 SubnetId routerSubnetId = new SubnetId(firstIp.getSubnetUUID());
270 Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
271 IidFactory.subnetIid(tenantId, routerSubnetId), rTx);
272 if (!potentialSubnet.isPresent()) {
273 LOG.warn("Illegal state - Subnet {} where is router port does not exist.", routerSubnetId.getValue());
276 IpPrefix ipSubnet = potentialSubnet.get().getIpPrefix();
277 NeutronSecurityRule routerRuleEgress = createRouterSecRule(port.getID(), tenantId, ipSubnet, consumerEpgId,
279 NeutronSecurityRule routerRuleIngress = createRouterSecRule(port.getID(), tenantId, ipSubnet, consumerEpgId,
281 return ImmutableList.of(routerRuleEgress, routerRuleIngress);
284 private static NeutronSecurityRule createRouterSecRule(String ruleUuid, TenantId tenantId, IpPrefix ipSubnet,
285 EndpointGroupId consumerEpgId, boolean isEgress) {
286 NeutronSecurityRule dhcpSecRule = new NeutronSecurityRule();
287 dhcpSecRule.setSecurityRuleGroupID(MappingUtils.EPG_ROUTER_ID.getValue());
288 dhcpSecRule.setSecurityRuleTenantID(tenantId.getValue());
289 dhcpSecRule.setSecurityRuleRemoteIpPrefix(Utils.getStringIpPrefix(ipSubnet));
291 dhcpSecRule.setSecurityRuleUUID(NeutronUtils.EGRESS + "__" + ruleUuid);
292 dhcpSecRule.setSecurityRuleDirection(NeutronUtils.EGRESS);
294 dhcpSecRule.setSecurityRuleUUID(NeutronUtils.INGRESS + "__" + ruleUuid);
295 dhcpSecRule.setSecurityRuleDirection(NeutronUtils.INGRESS);
297 if (ipSubnet.getIpv4Prefix() != null) {
298 dhcpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv4);
300 dhcpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv6);
306 public int canDetachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
307 LOG.trace("canDetachInterface - router: {} interface: {}", router, routerInterface);
308 // nothing to consider
309 return StatusCode.OK;
313 public void neutronRouterInterfaceDetached(NeutronRouter router, NeutronRouter_Interface routerInterface) {
314 LOG.trace("neutronRouterInterfaceDetached - router: {} interface: {}", router, routerInterface);
315 INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
316 if (subnetInterface == null) {
317 LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
321 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
322 TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
323 L3ContextId l3ContextId = new L3ContextId(router.getID());
324 SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
325 InstanceIdentifier<L3Context> l3ContextIid = IidFactory.l3ContextIid(tenantId, l3ContextId);
326 DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
327 IidFactory.l3ContextIid(tenantId, l3ContextId), rwTx);
329 Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
330 IidFactory.subnetIid(tenantId, subnetId), rwTx);
331 if (!potentialSubnet.isPresent()) {
332 LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
337 Subnet subnet = new SubnetBuilder(potentialSubnet.get()).setVirtualRouterIp(null).build();
338 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnetId), subnet);
340 L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
341 ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
342 if (fwCtx.getL2BridgeDomain() == null) {
343 LOG.warn("Illegal state - l2-flood-domain {} does not have a parent.", l2FdId.getValue());
348 Optional<NetworkMapping> potentialNetworkMapping = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
349 IidFactory.networkMappingIid(l2FdId), rwTx);
350 if (!potentialNetworkMapping.isPresent()) {
351 LOG.warn("Illegal state - network-mapping {} does not exist.", l2FdId.getValue());
356 L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(
357 potentialNetworkMapping.get().getL3ContextId()).build();
358 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BridgeDomain.getId()),
361 NeutronSubnet neutronSubnet = subnetInterface.getSubnet(subnetId.getValue());
362 List<NeutronPort> portsInNeutronSubnet = neutronSubnet.getPortsInSubnet();
363 for (NeutronPort port : portsInNeutronSubnet) {
364 boolean isPortAdded = NeutronPortAware.addNeutronPort(port, rwTx, epService);