Adding support for multiple classifiers per gate
[packetcable.git] / packetcable-driver / src / main / java / org / pcmm / gates / impl / ExtendedClassifier.java
1 /*
2  * (c) 2015 Cable Television Laboratories, Inc.  All rights reserved.
3  */
4
5 package org.pcmm.gates.impl;
6
7 import com.google.common.primitives.Bytes;
8 import org.pcmm.gates.IExtendedClassifier;
9 import org.umu.cops.stack.COPSMsgParser;
10
11 import java.net.Inet4Address;
12 import java.net.InetAddress;
13 import java.net.UnknownHostException;
14 import java.util.ArrayList;
15 import java.util.List;
16
17 /**
18  * Implementation of the IExtendedClassifier interface
19  */
20 public class ExtendedClassifier extends Classifier implements IExtendedClassifier {
21
22     /**
23      * IPv4 (for this class) and IPv6 (for extended IPv6Classifier) mask. When the address is zero, the mask is
24      * irrelevant else only packets with source IP address 'pkt.ip-src'
25      * will match if (pkt.ip-src AND classifier.ipmask-src) == classifier.ip-src.
26      */
27     protected final InetAddress srcMask;
28
29     /**
30      * IPv4 (for this class) and IPv6 (for extended IPv6Classifier) mask. When the address is zero, the mask is
31      * irrelevant else only packets with source IP address 'pkt.ip-dst'
32      * will match if (pkt.ip-dst AND classifier.ipmask-dst) == classifier.ip-dst.
33      */
34     protected final InetAddress dstMask;
35
36     /**
37      * Source Port End specifies the high-end TCP/UDP source port value. See super srcPort for low-end value.
38      */
39     protected final short srcPortEnd;
40
41     /**
42      * Destination Port End specifies the high-end TCP/UDP source port value. See super dstPort for low-end value.
43      */
44     protected final short dstPortEnd;
45
46     /**
47      * The classifiers identifier
48      */
49     protected final short classifierId;
50
51     /**
52      * Enumeration of the activation state
53      */
54     protected final ActivationState activationState;
55
56     /**
57      * The action value
58      */
59     protected final Action action;
60
61     /**
62      * Constructor
63      * @param protocol - the protocol being sent through the gate
64      * @param tosOverwrite - ENABLE/DISABLE
65      * @param tosMask - the mask
66      * @param srcAddress - the source IP
67      * @param dstAddress - the destination IP
68      * @param srcPortBegin - the source begin port
69      * @param dstPortBegin - the destination begin port
70      * @param priority - the priority value
71      * @param srcMask - the source IP mask
72      * @param dstMask - the destination IP mask
73      * @param srcPortEnd - the source start port
74      * @param dstPortEnd - the destination end port
75      * @param classifierId - the classifier identifier
76      * @param activationState - denotes the activation state
77      * @param action - the action
78      */
79     public ExtendedClassifier(final Protocol protocol, final byte tosOverwrite, final byte tosMask,
80                               final Inet4Address srcAddress, final Inet4Address dstAddress, final short srcPortBegin,
81                               final short dstPortBegin, final byte priority, final Inet4Address srcMask,
82                               final Inet4Address dstMask, final short srcPortEnd, final short dstPortEnd,
83                               final short classifierId, final ActivationState activationState, final Action action) {
84         super(IExtendedClassifier.STYPE, protocol, tosOverwrite, tosMask, srcAddress, dstAddress, srcPortBegin,
85                 dstPortBegin, priority);
86         if (srcMask == null) throw new IllegalArgumentException("Source IP Mask cannot be null");
87         if (dstMask == null) throw new IllegalArgumentException("Destination IP Mask cannot be null");
88         if (activationState == null) throw new IllegalArgumentException("Activation state must not be null");
89         if (action == null) throw new IllegalArgumentException("Action must not be null");
90         this.srcMask = srcMask;
91         this.dstMask = dstMask;
92         this.srcPortEnd = srcPortEnd;
93         this.dstPortEnd = dstPortEnd;
94         this.classifierId = classifierId;
95         this.activationState = activationState;
96         this.action = action;
97     }
98
99     /**
100      * Constructor for IPv6Classifier subclass
101      * @param sType - the type of classifier
102      * @param srcAddress - the source IP
103      * @param dstAddress - the destination IP
104      * @param srcPortBegin - the source begin port
105      * @param dstPortBegin - the destination begin port
106      * @param priority - the priority value
107      * @param srcPortEnd - the source start port
108      * @param dstPortEnd - the destination end port
109      * @param classifierId - the classifier identifier
110      * @param activationState - denotes the activation state
111      * @param action - the action
112      */
113     protected ExtendedClassifier(final byte sType, final InetAddress srcAddress, final InetAddress dstAddress,
114                                  final short srcPortBegin, final short dstPortBegin, final byte priority,
115                                  final short srcPortEnd, final short dstPortEnd, final short classifierId,
116                                  final ActivationState activationState, final Action action) {
117         super(sType, null, (byte)0, (byte)0, srcAddress, dstAddress, srcPortBegin, dstPortBegin, priority);
118         if (activationState == null) throw new IllegalArgumentException("Activation state must not be null");
119         if (action == null) throw new IllegalArgumentException("Action must not be null");
120         this.srcMask = null;
121         this.dstMask = null;
122         this.srcPortEnd = srcPortEnd;
123         this.dstPortEnd = dstPortEnd;
124         this.classifierId = classifierId;
125         this.activationState = activationState;
126         this.action = action;
127     }
128
129     @Override
130     public InetAddress getIPSourceMask() {
131         return srcMask;
132     }
133
134     @Override
135     public InetAddress getIPDestinationMask() {
136         return dstMask;
137     }
138
139     @Override
140     public short getSourcePortStart() {
141         return super.getSourcePort();
142     }
143
144     @Override
145     public short getSourcePortEnd() {
146         return srcPortEnd;
147     }
148
149     @Override
150     public short getDestinationPortStart() {
151         return super.getDestinationPort();
152     }
153
154     @Override
155     public short getDestinationPortEnd() {
156         return dstPortEnd;
157     }
158
159     @Override
160     public short getClassifierID() {
161         return classifierId;
162     }
163
164     @Override
165     public ActivationState getActivationState() {
166         return activationState;
167     }
168
169     @Override
170     public Action getAction() {
171         return action;
172     }
173
174     @Override
175     protected byte[] getBytes() {
176         final List<Byte> byteList = new ArrayList<>(Bytes.asList(COPSMsgParser.shortToBytes(protocol.getValue())));
177         byteList.add(tosOverwrite);
178         byteList.add(tosMask);
179         byteList.addAll(Bytes.asList(srcAddress.getAddress()));
180         byteList.addAll(Bytes.asList(srcMask.getAddress()));
181         byteList.addAll(Bytes.asList(dstAddress.getAddress()));
182         byteList.addAll(Bytes.asList(dstMask.getAddress()));
183         byteList.addAll(Bytes.asList(COPSMsgParser.shortToBytes(srcPort)));
184         byteList.addAll(Bytes.asList(COPSMsgParser.shortToBytes(srcPortEnd)));
185         byteList.addAll(Bytes.asList(COPSMsgParser.shortToBytes(dstPort)));
186         byteList.addAll(Bytes.asList(COPSMsgParser.shortToBytes(dstPortEnd)));
187         byteList.addAll(Bytes.asList(COPSMsgParser.shortToBytes(classifierId)));
188         byteList.add(priority);
189         byteList.add(activationState.getValue());
190         byteList.add(action.getByte());
191
192         // reserved padding
193         byteList.addAll(Bytes.asList((byte) 0, (byte) 0, (byte) 0));
194
195         return Bytes.toArray(byteList);
196     }
197
198     @Override
199     public boolean equals(final Object o) {
200         if (this == o) {
201             return true;
202         }
203         if (!(o instanceof ExtendedClassifier)) {
204             return false;
205         }
206         if (!super.equals(o)) {
207             return false;
208         }
209         final ExtendedClassifier that = (ExtendedClassifier) o;
210         return srcPortEnd == that.srcPortEnd && dstPortEnd == that.dstPortEnd && classifierId == that.classifierId &&
211                 activationState == that.activationState && action == that.action &&
212                 !(srcMask != null ? !srcMask.equals(that.srcMask) : that.srcMask != null) &&
213                 !(dstMask != null ? !dstMask.equals(that.dstMask) : that.dstMask != null);
214     }
215
216     @Override
217     public int hashCode() {
218         int result = super.hashCode();
219         result = 31 * result + (srcMask != null ? srcMask.hashCode() : 0);
220         result = 31 * result + (dstMask != null ? dstMask.hashCode() : 0);
221         result = 31 * result + (int) srcPortEnd;
222         result = 31 * result + (int) dstPortEnd;
223         result = 31 * result + (int) classifierId;
224         result = 31 * result + (int) activationState.getValue();
225         result = 31 * result + (int) action.getByte();
226         return result;
227     }
228
229     /**
230      * Returns a ExtendedClassifier object from a byte array
231      * @param data - the data to parse
232      * @return - the object or null if cannot be parsed
233      * TODO - make me more robust as exceptions can be swallowed here.
234      */
235     public static ExtendedClassifier parse(final byte[] data) {
236         final List<Byte> bytes = new ArrayList<>(Bytes.asList(data));
237
238         try {
239             return new ExtendedClassifier(Protocol.valueOf(COPSMsgParser.bytesToShort(data[0], data[1])),
240                     data[2], data[3],
241                     (Inet4Address)InetAddress.getByAddress(Bytes.toArray(bytes.subList(4, 8))),
242                     (Inet4Address)InetAddress.getByAddress(Bytes.toArray(bytes.subList(8, 12))),
243                     COPSMsgParser.bytesToShort(data[20], data[21]), COPSMsgParser.bytesToShort(data[24], data[25]),
244                     data[30], (Inet4Address)InetAddress.getByAddress(Bytes.toArray(bytes.subList(12, 16))),
245                     (Inet4Address)InetAddress.getByAddress(Bytes.toArray(bytes.subList(16, 20))),
246                     COPSMsgParser.bytesToShort(data[22], data[23]), COPSMsgParser.bytesToShort(data[26], data[27]),
247                     COPSMsgParser.bytesToShort(data[28], data[29]), ActivationState.valueOf(data[31]),
248                     Action.getFromByte(data[32]));
249         } catch (UnknownHostException e) {
250             return null;
251         }
252     }
253
254 }