Merge "Move utility function to common place."
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / flow / PortSecurity.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.flow;
10
11 import java.util.Map;
12 import java.util.Set;
13
14 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
15 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
16 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
17 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
18 import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
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.inventory.rev130819.FlowId;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.EndpointLocation.LocationType;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41  * Manage the table that enforces port security
42  * @author readams
43  */
44 public class PortSecurity extends FlowTable {
45     protected static final Logger LOG =
46             LoggerFactory.getLogger(PortSecurity.class);
47
48     public static final short TABLE_ID = 0;
49
50     public PortSecurity(OfContext ctx) {
51         super(ctx);
52     }
53
54     @Override
55     public short getTableId() {
56         return TABLE_ID;
57     }
58
59     @Override
60     public void sync(ReadWriteTransaction t,
61                      InstanceIdentifier<Table> tiid,
62                      Map<String, FlowCtx> flowMap,
63                      NodeId nodeId, PolicyInfo policyInfo, Dirty dirty) {
64         // Allow traffic from tunnel and external ports
65         NodeConnectorId tunnelIf = ctx.getSwitchManager().getTunnelPort(nodeId);
66         if (tunnelIf != null)
67             allowFromPort(t, tiid, flowMap, tunnelIf);
68         Set<NodeConnectorId> external =
69                 ctx.getSwitchManager().getExternalPorts(nodeId);
70         for (NodeConnectorId extIf: external) {
71             allowFromPort(t, tiid, flowMap, extIf);
72         }
73
74         // Default drop all
75         dropFlow(t, tiid, flowMap, 1, null);
76
77         // Drop IP traffic that doesn't match a source IP rule
78         dropFlow(t, tiid, flowMap, 110, FlowUtils.ARP);
79         dropFlow(t, tiid, flowMap, 111, FlowUtils.IPv4);
80         dropFlow(t, tiid, flowMap, 112, FlowUtils.IPv6);
81
82         for (EgKey sepg : ctx.getEndpointManager().getGroupsForNode(nodeId)) {
83             for (Endpoint e : ctx.getEndpointManager().getEPsForNode(nodeId, sepg)) {
84                 OfOverlayContext ofc = e.getAugmentation(OfOverlayContext.class);
85                 if (ofc != null && ofc.getNodeConnectorId() != null &&
86                         (ofc.getLocationType() == null ||
87                         LocationType.Internal.equals(ofc.getLocationType()))) {
88                     // Allow layer 3 traffic (ARP and IP) with the correct
89                     // source IP, MAC, and source port
90                     l3flow(t, tiid, flowMap, e, ofc, 120, false);
91                     l3flow(t, tiid, flowMap, e, ofc, 121, true);
92                     l3DhcpDoraFlow(t, tiid, flowMap, e, ofc, 115);
93
94                     // Allow layer 2 traffic with the correct source MAC and
95                     // source port (note lower priority than drop IP rules)
96                     l2flow(t, tiid, flowMap, e, ofc, 100);
97                 }
98             }
99         }
100     }
101
102     private void allowFromPort(ReadWriteTransaction t,
103                                InstanceIdentifier<Table> tiid,
104                                Map<String, FlowCtx> flowMap,
105                                NodeConnectorId port) {
106         FlowId flowid = new FlowId(new StringBuilder()
107             .append("allow|")
108             .append(port.getValue())
109             .toString());
110         if (visit(flowMap, flowid.getValue())) {
111             FlowBuilder flowb = base()
112                 .setId(flowid)
113                 .setPriority(Integer.valueOf(200))
114                 .setMatch(new MatchBuilder()
115                     .setInPort(port)
116                     .build())
117                 .setInstructions(FlowUtils.gotoTableInstructions((short)(getTableId()+1)));
118             writeFlow(t, tiid, flowb.build());
119         }
120     }
121
122     private void l2flow(ReadWriteTransaction t,
123                         InstanceIdentifier<Table> tiid,
124                         Map<String, FlowCtx> flowMap,
125                         Endpoint e, OfOverlayContext ofc,
126                         Integer priority) {
127         FlowId flowid = new FlowId(new StringBuilder()
128             .append(ofc.getNodeConnectorId().getValue())
129             .append("|")
130             .append(e.getMacAddress().getValue())
131             .toString());
132         if (visit(flowMap, flowid.getValue())) {
133             FlowBuilder flowb = base()
134                 .setPriority(priority)
135                 .setId(flowid)
136                 .setMatch(new MatchBuilder()
137                     .setEthernetMatch(FlowUtils.ethernetMatch(e.getMacAddress(),
138                                                               null, null))
139                     .setInPort(ofc.getNodeConnectorId())
140                     .build())
141                 .setInstructions(FlowUtils.gotoTableInstructions((short)(TABLE_ID + 1)));
142
143             writeFlow(t, tiid, flowb.build());
144         }
145     }
146
147     private void l3DhcpDoraFlow(ReadWriteTransaction t,
148                                 InstanceIdentifier<Table> tiid,
149                                 Map<String, FlowCtx> flowMap,
150                                 Endpoint e, OfOverlayContext ofc,
151                                 Integer priority) {
152
153         Long etherType= FlowUtils.IPv4;
154         // DHCP DORA destination is broadcast
155         String ikey="255.255.255.255/32";
156         Layer3Match m=new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(ikey)).build();
157
158         FlowId flowid = new FlowId(new StringBuilder()
159         .append(ofc.getNodeConnectorId().getValue())
160         .append("|")
161         .append(e.getMacAddress().getValue())
162         .append("|dhcp|")
163         .append(etherType)
164         .toString());
165         if (visit(flowMap, flowid.getValue())) {
166             Flow flow = base()
167                     .setPriority(priority)
168                     .setId(flowid)
169                     .setMatch(new MatchBuilder()
170                     .setEthernetMatch(FlowUtils.ethernetMatch(e.getMacAddress(),
171                             null,
172                             etherType))
173                             .setLayer3Match(m)
174                             .setInPort(ofc.getNodeConnectorId())
175                             .build())
176                             .setInstructions(FlowUtils.gotoTableInstructions((short)(TABLE_ID + 1)))
177                             .build();
178
179             writeFlow(t, tiid, flow);
180         }
181     }
182
183     private void l3flow(ReadWriteTransaction t,
184                         InstanceIdentifier<Table> tiid,
185                         Map<String, FlowCtx> flowMap,
186                         Endpoint e, OfOverlayContext ofc,
187                         Integer priority,
188                         boolean arp) {
189         if (e.getL3Address() == null) return;
190         for (L3Address l3 : e.getL3Address()) {
191             if (l3.getIpAddress() == null) continue;
192             Layer3Match m = null;
193             Long etherType = null;
194             String ikey = null;
195             if (l3.getIpAddress().getIpv4Address() != null) {
196                 ikey = l3.getIpAddress().getIpv4Address().getValue()+"/32";
197                 if (arp) {
198                     m = new ArpMatchBuilder()
199                         .setArpSourceTransportAddress(new Ipv4Prefix(ikey))
200                         .build();
201                     etherType = FlowUtils.ARP;
202                 } else {
203                     m = new Ipv4MatchBuilder()
204                         .setIpv4Source(new Ipv4Prefix(ikey))
205                         .build();
206                     etherType = FlowUtils.IPv4;
207                 }
208             } else if (l3.getIpAddress().getIpv6Address() != null) {
209                 if (arp) continue;
210                 ikey = l3.getIpAddress().getIpv6Address().getValue()+"/128";
211                 m = new Ipv6MatchBuilder()
212                     .setIpv6Source(new Ipv6Prefix(ikey))
213                     .build();
214                 etherType = FlowUtils.IPv6;
215             } else {
216                 continue;
217             }
218             FlowId flowid = new FlowId(new StringBuilder()
219                 .append(ofc.getNodeConnectorId().getValue())
220                 .append("|")
221                 .append(e.getMacAddress().getValue())
222                 .append("|")
223                 .append(ikey)
224                 .append("|")
225                 .append(etherType)
226                 .toString());
227             if (visit(flowMap, flowid.getValue())) {
228                 Flow flow = base()
229                     .setPriority(priority)
230                     .setId(flowid)
231                     .setMatch(new MatchBuilder()
232                         .setEthernetMatch(FlowUtils.ethernetMatch(e.getMacAddress(),
233                                                                   null,
234                                                                   etherType))
235                         .setLayer3Match(m)
236                         .setInPort(ofc.getNodeConnectorId())
237                         .build())
238                     .setInstructions(FlowUtils.gotoTableInstructions((short)(TABLE_ID + 1)))
239                     .build();
240
241                 writeFlow(t, tiid, flow);
242             }
243         }
244     }
245 }