Implementation of IP address classifier.
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / sf / IpAddressClassifier.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. 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.groupbasedpolicy.renderer.ofoverlay.sf;
10
11 import java.net.Inet4Address;
12 import java.net.InetAddress;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.List;
16 import java.util.Map;
17
18 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.ParameterBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.IsRequired;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.Type;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinitionBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6Match;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
36
37 import com.google.common.base.Strings;
38 import com.google.common.collect.ImmutableList;
39 import com.google.common.collect.ImmutableMap;
40 import com.google.common.net.InetAddresses;
41
42 /**
43  * Match on the IP address of IP traffic
44  */
45 public class IpAddressClassifier extends EtherTypeClassifier {
46     public static final ClassifierDefinitionId ID = new ClassifierDefinitionId("55b83ba4-a741-4d26-91ca-7cd197750a3f");
47
48     protected static final String SRC_ADDR = "src_addr";
49     protected static final String DST_ADDR = "dst_addr";
50     protected static final ClassifierDefinition DEF = new ClassifierDefinitionBuilder()
51             .setId(ID)
52             .setParent(EtherTypeClassifier.ID)
53             .setName(new ClassifierName("ip_address"))
54             .setDescription(new Description("Match on the IP address of IP traffic"))
55             .setParameter(
56                     ImmutableList.of(
57                             new ParameterBuilder()
58                                     .setName(new ParameterName(SRC_ADDR))
59                                     .setDescription(new Description("Source IP prefix to match against."))
60                                     .setIsRequired(IsRequired.Optional)
61                                     .setType(Type.String)
62                                     .build(),
63                             new ParameterBuilder()
64                                     .setName(new ParameterName(DST_ADDR))
65                                     .setDescription(new Description("Destination IP prefix to match against."))
66                                     .setIsRequired(IsRequired.Optional)
67                                     .setType(Type.String).build()))
68                                     .build();
69     private static final Map<String, Object> ipv4 = ImmutableMap.<String, Object> of(TYPE, FlowUtils.IPv4);
70     private static final Map<String, Object> ipv6 = ImmutableMap.<String, Object> of(TYPE, FlowUtils.IPv6);
71
72     private enum IpAddressContext {
73         SRC, DST
74     }
75
76     @Override
77     public ClassifierDefinitionId getId() {
78         return ID;
79     }
80
81     @Override
82     public ClassifierDefinition getClassDef() {
83         return DEF;
84     }
85
86     @Override
87     public List<MatchBuilder> updateMatch(List<MatchBuilder> matches, Map<String, Object> params) {
88         Object t = params.get(SRC_ADDR);
89         String srcAddr = null;
90         if (t instanceof String) {
91             srcAddr = (String) t;
92         }
93         t = params.get(DST_ADDR);
94         String dstAddr = null;
95         if (t instanceof String) {
96             dstAddr = (String) t;
97         }
98         List<MatchBuilder> r = new ArrayList<>();
99         for (MatchBuilder b : matches) {
100             if (srcAddr != null && dstAddr != null) {
101                 boolean isSrcIpv4Addr = isIpv4Address(srcAddr);
102                 boolean isDstIpv4Addr = isIpv4Address(dstAddr);
103                 if (isSrcIpv4Addr != isDstIpv4Addr) {
104                     throw new IllegalArgumentException("Ip address [" + srcAddr + "] is not the same version as ["
105                             + dstAddr + "].");
106                 }
107                 r.addAll(updateMatch(b, srcAddr, dstAddr, getIpVersion(isSrcIpv4Addr)));
108             } else if (srcAddr == null && dstAddr == null) {
109                 r.addAll(super.updateMatch(Collections.singletonList(new MatchBuilder(b.build())), ipv4));
110                 r.addAll(super.updateMatch(Collections.singletonList(new MatchBuilder(b.build())), ipv6));
111             } else {
112                 if (srcAddr != null) {
113                     r.addAll(updateMatch(new MatchBuilder(b.build()), srcAddr, null,
114                             getIpVersion(isIpv4Address(srcAddr))));
115                 } else {
116                     r.addAll(updateMatch(new MatchBuilder(b.build()), null, dstAddr,
117                             getIpVersion(isIpv4Address(dstAddr))));
118                 }
119             }
120         }
121         return r;
122     }
123
124     private List<MatchBuilder> updateMatch(MatchBuilder matchBuilder, String srcAddr, String dstAddr,
125             Map<String, Object> params) {
126         List<MatchBuilder> r = super.updateMatch(Collections.singletonList(matchBuilder), params);
127         Long ipVersion = (Long) params.get(TYPE);
128         for (MatchBuilder mb : r) {
129             Layer3Match l3m = mb.getLayer3Match();
130             l3m = updateIpAddressField(ipVersion, srcAddr, IpAddressContext.SRC, l3m);
131             l3m = updateIpAddressField(ipVersion, dstAddr, IpAddressContext.DST, l3m);
132             mb.setLayer3Match(l3m);
133         }
134         return r;
135     }
136
137     private Map<String, Object> getIpVersion(boolean isIpv4) {
138         if (isIpv4 == true) {
139             return ipv4;
140         }
141         return ipv6;
142     }
143
144     private boolean isIpv4Address(String cidr) {
145         String[] ipAndPrefix = cidr.split("/");
146         if (ipAndPrefix.length != 2) {
147             throw new IllegalStateException(cidr + " does not match CIDR format.");
148         }
149         InetAddress ip = InetAddresses.forString(ipAndPrefix[0]);
150         if (ip instanceof Inet4Address) {
151             return true;
152         }
153         return false;
154     }
155
156     private Layer3Match updateIpAddressField(Long ipVersion, String ipAddr, IpAddressContext ctx, Layer3Match l3m) {
157         if (Strings.isNullOrEmpty(ipAddr)) {
158             return l3m;
159         }
160         if (ipVersion.equals(FlowUtils.IPv4)) {
161             l3m = updateIpv4AddressField(ipAddr, ctx, l3m);
162         } else if (ipVersion.equals(FlowUtils.IPv6)) {
163             l3m = updateIpv6AddressField(ipAddr, ctx, l3m);
164         }
165         return l3m;
166     }
167
168     private Layer3Match updateIpv4AddressField(String ipAddr, IpAddressContext ctx, Layer3Match l3match) {
169         Ipv4MatchBuilder ipv4mb;
170         if (l3match == null) {
171             ipv4mb = new Ipv4MatchBuilder();
172         } else {
173             ipv4mb = new Ipv4MatchBuilder((Ipv4Match) l3match);
174         }
175         if (ctx.equals(IpAddressContext.SRC)) {
176             return ipv4mb.setIpv4Source(new Ipv4Prefix(ipAddr)).build();
177         }
178         return ipv4mb.setIpv4Destination(new Ipv4Prefix(ipAddr)).build();
179     }
180
181     private Layer3Match updateIpv6AddressField(String ipAddr, IpAddressContext ctx, Layer3Match l3match) {
182         Ipv6MatchBuilder ipv6mb;
183         if (l3match == null) {
184             ipv6mb = new Ipv6MatchBuilder();
185         } else {
186             ipv6mb = new Ipv6MatchBuilder((Ipv6Match) l3match);
187         }
188         if (ctx.equals(IpAddressContext.SRC)) {
189             return ipv6mb.setIpv6Source(new Ipv6Prefix(ipAddr)).build();
190         }
191         return ipv6mb.setIpv6Destination(new Ipv6Prefix(ipAddr)).build();
192     }
193 }