2309defb00a5ad69c9b46bcd792508228718d20a
[vpnservice.git] / dhcpservice / dhcpservice-impl / src / main / java / org / opendaylight / vpnservice / dhcpservice / DhcpManager.java
1 /*
2  * Copyright (c) 2015 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 package org.opendaylight.vpnservice.dhcpservice;
9
10 import org.opendaylight.vpnservice.neutronvpn.interfaces.INeutronVpnManager;
11 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey;
12 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
13
14 import com.google.common.base.Optional;
15
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
19 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
20
21 import java.math.BigInteger;
22 import java.util.ArrayList;
23 import java.util.List;
24
25 import com.google.common.util.concurrent.FutureCallback;
26
27 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
28 import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
29 import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
30 import org.opendaylight.vpnservice.mdsalutil.ActionType;
31 import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
32 import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
33 import org.opendaylight.vpnservice.mdsalutil.InstructionType;
34 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
35 import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
36 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
37 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
38 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
39 import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 public class DhcpManager implements AutoCloseable {
46
47     private static final Logger logger = LoggerFactory.getLogger(DhcpManager.class);
48     private final DataBroker broker;
49     IMdsalApiManager mdsalUtil;
50
51     private int dhcpOptLeaseTime = 0;
52     private int dhcpOptRenewalTime = 0;
53     private int dhcpOptRebindingTime = 0;
54     private String dhcpOptDefDomainName;
55     private INeutronVpnManager neutronVpnService;
56
57     private static final FutureCallback<Void> DEFAULT_CALLBACK =
58         new FutureCallback<Void>() {
59             public void onSuccess(Void result) {
60                 logger.debug("Success in Datastore write operation");
61             }
62             public void onFailure(Throwable error) {
63                 logger.error("Error in Datastore write operation", error);
64             };
65         };
66
67     /**
68     * @param db - dataBroker reference
69     */
70     public DhcpManager(final DataBroker db) {
71         broker = db;
72         configureLeaseDuration(DHCPMConstants.DEFAULT_LEASE_TIME);
73     }
74
75     public void setMdsalManager(IMdsalApiManager mdsalManager) {
76         this.mdsalUtil = mdsalManager;
77     }
78
79     public void setNeutronVpnService(INeutronVpnManager neutronVpnService) {
80         logger.debug("Setting NeutronVpn dependency");
81         this.neutronVpnService = neutronVpnService;
82     }
83
84     @Override
85     public void close() throws Exception {
86         logger.info("DHCP Manager Closed");
87     }
88
89     public void installDhcpEntries(BigInteger dpnId) {
90         logger.debug("Installing Default DHCP Flow tp DPN: {}", dpnId);
91         setupDefaultDhcpFlow(dpnId, NwConstants.DHCP_TABLE, NwConstants.ADD_FLOW);
92     }
93
94     private void setupDefaultDhcpFlow(BigInteger dpId,  short tableId, int addOrRemove) {
95
96         List<MatchInfo> matches = new ArrayList<MatchInfo>();
97
98         matches.add(new MatchInfo(MatchFieldType.eth_type,
99                 new long[] { NwConstants.ETHTYPE_IPV4 }));
100         matches.add(new MatchInfo(MatchFieldType.ip_proto,
101                 new long[] { IPProtocols.UDP.intValue() }));
102         matches.add(new MatchInfo(MatchFieldType.udp_src,
103                 new long[] { DHCPMConstants.dhcpClientPort }));
104         matches.add(new MatchInfo(MatchFieldType.udp_dst,
105                 new long[] { DHCPMConstants.dhcpServerPort }));
106
107         List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
108         List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
109
110         // Punt to controller
111         actionsInfos.add(new ActionInfo(ActionType.punt_to_controller,
112                 new String[] {}));
113         instructions.add(new InstructionInfo(InstructionType.write_actions,
114                 actionsInfos));
115         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
116                 getDefaultDhcpFlowRef(dpId, tableId),DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
117                 DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
118         mdsalUtil.installFlow(flowEntity);
119     }
120
121     private String getDefaultDhcpFlowRef(BigInteger dpId, long tableId) {
122         return new StringBuffer().append(DHCPMConstants.FLOWID_PREFIX).append(dpId)
123                         .append(NwConstants.FLOWID_SEPARATOR).append(tableId).toString();
124     }
125
126     public int setLeaseDuration(int leaseDuration) {
127         configureLeaseDuration(leaseDuration);
128         return getDhcpLeaseTime();
129     }
130
131     public String setDefaultDomain(String defaultDomain) {
132         this.dhcpOptDefDomainName = defaultDomain;
133         return getDhcpDefDomain();
134     }
135
136     protected int getDhcpLeaseTime() {
137         return this.dhcpOptLeaseTime;
138     }
139
140     protected int getDhcpRenewalTime() {
141         return this.dhcpOptLeaseTime;
142     }
143
144     protected int getDhcpRebindingTime() {
145         return this.dhcpOptLeaseTime;
146     }
147
148     protected String getDhcpDefDomain() {
149         return this.dhcpOptDefDomainName;
150     }
151
152     private void configureLeaseDuration(int leaseTime) {
153         this.dhcpOptLeaseTime = leaseTime;
154         if(leaseTime > 0) {
155             this.dhcpOptRenewalTime = this.dhcpOptLeaseTime/2;
156             this.dhcpOptRebindingTime = (this.dhcpOptLeaseTime*7)/8;
157         } else {
158             this.dhcpOptRenewalTime = -1;
159             this.dhcpOptRebindingTime = -1;
160         }
161     }
162
163     public Subnet getNeutronSubnet(Port nPort) {
164         if (nPort != null) {
165             try {
166                 return neutronVpnService.getNeutronSubnet(nPort.getFixedIps().get(0).getSubnetId());
167             } catch (Exception e) {
168                 logger.warn("Failed to get Neutron Subnet from Port: {}", e);
169             }
170         }
171         return null;
172     }
173
174     public Port getNeutronPort(String name) {
175         try {
176             return neutronVpnService.getNeutronPort(name);
177         } catch (Exception ex) {
178             logger.trace("In getNeutronPort interface name passed {} exception message {}.", name, ex.getMessage());
179             return null;
180         }
181     }
182
183     public void installDhcpEntries(BigInteger dpnId, String vmMacAddress) {
184         setupDhcpFlowEntry(dpnId, NwConstants.DHCP_TABLE, vmMacAddress, NwConstants.ADD_FLOW);
185     }
186
187     private void setupDhcpFlowEntry(BigInteger dpId, short tableId, String vmMacAddress, int addOrRemove) {
188         if (dpId == null || dpId == DHCPMConstants.INVALID_DPID || vmMacAddress == null) {
189             return;
190         }
191         List<MatchInfo> matches = new ArrayList<MatchInfo>();
192
193         matches.add(new MatchInfo(MatchFieldType.eth_type,
194                 new long[] { NwConstants.ETHTYPE_IPV4 }));
195         matches.add(new MatchInfo(MatchFieldType.ip_proto,
196                 new long[] { IPProtocols.UDP.intValue() }));
197         matches.add(new MatchInfo(MatchFieldType.udp_src,
198                 new long[] { DHCPMConstants.dhcpClientPort }));
199         matches.add(new MatchInfo(MatchFieldType.udp_dst,
200                 new long[] { DHCPMConstants.dhcpServerPort }));
201         matches.add(new MatchInfo(MatchFieldType.eth_src,
202                 new String[] { vmMacAddress }));
203
204         List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
205         List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
206
207         // Punt to controller
208         actionsInfos.add(new ActionInfo(ActionType.punt_to_controller,
209                 new String[] {}));
210         instructions.add(new InstructionInfo(InstructionType.write_actions,
211                 actionsInfos));
212         if (addOrRemove == NwConstants.DEL_FLOW) {
213             FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
214                     getDhcpFlowRef(dpId, tableId, vmMacAddress),
215                     DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
216                     DHCPMConstants.COOKIE_DHCP_BASE, matches, null);
217             logger.trace("Removing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
218             mdsalUtil.removeFlow(flowEntity);
219         } else {
220             FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
221                     getDhcpFlowRef(dpId, tableId, vmMacAddress),DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
222                     DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
223             logger.trace("Installing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
224             mdsalUtil.installFlow(flowEntity);
225         }
226     }
227
228     private String getDhcpFlowRef(BigInteger dpId, long tableId, String vmMacAddress) {
229         return new StringBuffer().append(DHCPMConstants.FLOWID_PREFIX)
230                 .append(dpId).append(NwConstants.FLOWID_SEPARATOR)
231                 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
232                 .append(vmMacAddress).toString();
233     }
234
235     public void unInstallDhcpEntries(BigInteger dpId, String vmMacAddress) {
236         setupDhcpFlowEntry(dpId, NwConstants.DHCP_TABLE, vmMacAddress, NwConstants.DEL_FLOW);
237     }
238
239     public void setupTableMissForDhcpTable(BigInteger dpId) {
240         List<MatchInfo> matches = new ArrayList<MatchInfo>();
241         List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
242         instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.LPORT_DISPATCHER_TABLE }));
243
244         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.DHCP_TABLE, "DHCPTableMissFlow",
245                 0, "DHCP Table Miss Flow", 0, 0,
246                 DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
247         mdsalUtil.installFlow(flowEntity);
248     }
249 }