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