blob: 3f8ff6c2116277c6388272ed17e749b0fec66a33 [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001package net.floodlightcontroller.firewall;
2
3import java.util.Collection;
4import java.util.Collections;
5import java.util.HashMap;
6import java.util.Iterator;
7import java.util.List;
8import java.util.Map;
9
10import org.openflow.protocol.OFMessage;
11import org.openflow.protocol.OFPacketIn;
12import org.openflow.protocol.OFType;
13
14import net.floodlightcontroller.core.FloodlightContext;
15import net.floodlightcontroller.core.IOFMessageListener;
16import net.floodlightcontroller.core.IOFSwitch;
17import net.floodlightcontroller.core.module.FloodlightModuleContext;
18import net.floodlightcontroller.core.module.FloodlightModuleException;
19import net.floodlightcontroller.core.module.IFloodlightModule;
20import net.floodlightcontroller.core.module.IFloodlightService;
21
22import net.floodlightcontroller.core.IFloodlightProviderService;
23import net.floodlightcontroller.devicemanager.IDeviceService;
24
25import java.util.ArrayList;
26import net.floodlightcontroller.packet.Ethernet;
27import net.floodlightcontroller.packet.IPv4;
28import net.floodlightcontroller.restserver.IRestApiService;
29import net.floodlightcontroller.routing.IRoutingDecision;
30import net.floodlightcontroller.routing.RoutingDecision;
31import net.floodlightcontroller.storage.IResultSet;
32import net.floodlightcontroller.storage.IStorageSourceService;
33import net.floodlightcontroller.storage.StorageException;
34
35import org.slf4j.Logger;
36import org.slf4j.LoggerFactory;
37
38/**
39 * Stateless firewall implemented as a Google Summer of Code project.
40 * Configuration done through REST API
41 *
42 * @author Amer Tahir
43 * @edited KC Wang
44 */
45public class Firewall implements IFirewallService, IOFMessageListener,
46 IFloodlightModule {
47
48 // service modules needed
49 protected IFloodlightProviderService floodlightProvider;
50 protected IStorageSourceService storageSource;
51 protected IRestApiService restApi;
52 protected static Logger logger;
53
54 protected List<FirewallRule> rules; // protected by synchronized
55 protected boolean enabled;
56 protected int subnet_mask = IPv4.toIPv4Address("255.255.255.0");
57
58 // constant strings for storage/parsing
59 public static final String TABLE_NAME = "controller_firewallrules";
60 public static final String COLUMN_RULEID = "ruleid";
61 public static final String COLUMN_DPID = "dpid";
62 public static final String COLUMN_IN_PORT = "in_port";
63 public static final String COLUMN_DL_SRC = "dl_src";
64 public static final String COLUMN_DL_DST = "dl_dst";
65 public static final String COLUMN_DL_TYPE = "dl_type";
66 public static final String COLUMN_NW_SRC_PREFIX = "nw_src_prefix";
67 public static final String COLUMN_NW_SRC_MASKBITS = "nw_src_maskbits";
68 public static final String COLUMN_NW_DST_PREFIX = "nw_dst_prefix";
69 public static final String COLUMN_NW_DST_MASKBITS = "nw_dst_maskbits";
70 public static final String COLUMN_NW_PROTO = "nw_proto";
71 public static final String COLUMN_TP_SRC = "tp_src";
72 public static final String COLUMN_TP_DST = "tp_dst";
73 public static final String COLUMN_WILDCARD_DPID = "wildcard_dpid";
74 public static final String COLUMN_WILDCARD_IN_PORT = "wildcard_in_port";
75 public static final String COLUMN_WILDCARD_DL_SRC = "wildcard_dl_src";
76 public static final String COLUMN_WILDCARD_DL_DST = "wildcard_dl_dst";
77 public static final String COLUMN_WILDCARD_DL_TYPE = "wildcard_dl_type";
78 public static final String COLUMN_WILDCARD_NW_SRC = "wildcard_nw_src";
79 public static final String COLUMN_WILDCARD_NW_DST = "wildcard_nw_dst";
80 public static final String COLUMN_WILDCARD_NW_PROTO = "wildcard_nw_proto";
81 public static final String COLUMN_WILDCARD_TP_SRC = "wildcard_tp_src";
82 public static final String COLUMN_WILDCARD_TP_DST = "wildcard_tp_dst";
83 public static final String COLUMN_PRIORITY = "priority";
84 public static final String COLUMN_ACTION = "action";
85 public static String ColumnNames[] = { COLUMN_RULEID, COLUMN_DPID,
86 COLUMN_IN_PORT, COLUMN_DL_SRC, COLUMN_DL_DST, COLUMN_DL_TYPE,
87 COLUMN_NW_SRC_PREFIX, COLUMN_NW_SRC_MASKBITS, COLUMN_NW_DST_PREFIX,
88 COLUMN_NW_DST_MASKBITS, COLUMN_NW_PROTO, COLUMN_TP_SRC,
89 COLUMN_TP_DST, COLUMN_WILDCARD_DPID, COLUMN_WILDCARD_IN_PORT,
90 COLUMN_WILDCARD_DL_SRC, COLUMN_WILDCARD_DL_DST,
91 COLUMN_WILDCARD_DL_TYPE, COLUMN_WILDCARD_NW_SRC,
92 COLUMN_WILDCARD_NW_DST, COLUMN_WILDCARD_NW_PROTO, COLUMN_PRIORITY,
93 COLUMN_ACTION };
94
95 @Override
96 public String getName() {
97 return "firewall";
98 }
99
100 @Override
101 public boolean isCallbackOrderingPrereq(OFType type, String name) {
102 // no prereq
103 return false;
104 }
105
106 @Override
107 public boolean isCallbackOrderingPostreq(OFType type, String name) {
108 return (type.equals(OFType.PACKET_IN) && name.equals("forwarding"));
109 }
110
111 @Override
112 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
113 Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>();
114 l.add(IFirewallService.class);
115 return l;
116 }
117
118 @Override
119 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
120 Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
121 // We are the class that implements the service
122 m.put(IFirewallService.class, this);
123 return m;
124 }
125
126 @Override
127 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
128 Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>();
129 l.add(IFloodlightProviderService.class);
130 l.add(IStorageSourceService.class);
131 l.add(IRestApiService.class);
132 return l;
133 }
134
135 /**
136 * Reads the rules from the storage and creates a sorted arraylist of
137 * FirewallRule from them.
138 *
139 * Similar to getStorageRules(), which only reads contents for REST GET and
140 * does no parsing, checking, nor putting into FirewallRule objects
141 *
142 * @return the sorted arraylist of FirewallRule instances (rules from
143 * storage)
144 */
145 protected ArrayList<FirewallRule> readRulesFromStorage() {
146 ArrayList<FirewallRule> l = new ArrayList<FirewallRule>();
147
148 try {
149 Map<String, Object> row;
150
151 // (..., null, null) for no predicate, no ordering
152 IResultSet resultSet = storageSource.executeQuery(TABLE_NAME,
153 ColumnNames, null, null);
154
155 // put retrieved rows into FirewallRules
156 for (Iterator<IResultSet> it = resultSet.iterator(); it.hasNext();) {
157 row = it.next().getRow();
158 // now, parse row
159 FirewallRule r = new FirewallRule();
160 if (!row.containsKey(COLUMN_RULEID)
161 || !row.containsKey(COLUMN_DPID)) {
162 logger.error(
163 "skipping entry with missing required 'ruleid' or 'switchid' entry: {}",
164 row);
165 return l;
166 }
167 try {
168 r.ruleid = Integer
169 .parseInt((String) row.get(COLUMN_RULEID));
170 r.dpid = Long.parseLong((String) row.get(COLUMN_DPID));
171
172 for (String key : row.keySet()) {
173 if (row.get(key) == null)
174 continue;
175 if (key.equals(COLUMN_RULEID)
176 || key.equals(COLUMN_DPID)
177 || key.equals("id")) {
178 continue; // already handled
179 }
180
181 else if (key.equals(COLUMN_IN_PORT)) {
182 r.in_port = Short.parseShort((String) row
183 .get(COLUMN_IN_PORT));
184 }
185
186 else if (key.equals(COLUMN_DL_SRC)) {
187 r.dl_src = Long.parseLong((String) row
188 .get(COLUMN_DL_SRC));
189 }
190
191 else if (key.equals(COLUMN_DL_DST)) {
192 r.dl_dst = Long.parseLong((String) row
193 .get(COLUMN_DL_DST));
194 }
195
196 else if (key.equals(COLUMN_DL_TYPE)) {
197 r.dl_type = Short.parseShort((String) row
198 .get(COLUMN_DL_TYPE));
199 }
200
201 else if (key.equals(COLUMN_NW_SRC_PREFIX)) {
202 r.nw_src_prefix = Integer.parseInt((String) row
203 .get(COLUMN_NW_SRC_PREFIX));
204 }
205
206 else if (key.equals(COLUMN_NW_SRC_MASKBITS)) {
207 r.nw_src_maskbits = Integer.parseInt((String) row
208 .get(COLUMN_NW_SRC_MASKBITS));
209 }
210
211 else if (key.equals(COLUMN_NW_DST_PREFIX)) {
212 r.nw_dst_prefix = Integer.parseInt((String) row
213 .get(COLUMN_NW_DST_PREFIX));
214 }
215
216 else if (key.equals(COLUMN_NW_DST_MASKBITS)) {
217 r.nw_dst_maskbits = Integer.parseInt((String) row
218 .get(COLUMN_NW_DST_MASKBITS));
219 }
220
221 else if (key.equals(COLUMN_NW_PROTO)) {
222 r.nw_proto = Short.parseShort((String) row
223 .get(COLUMN_NW_PROTO));
224 }
225
226 else if (key.equals(COLUMN_TP_SRC)) {
227 r.tp_src = Short.parseShort((String) row
228 .get(COLUMN_TP_SRC));
229 }
230
231 else if (key.equals(COLUMN_TP_DST)) {
232 r.tp_dst = Short.parseShort((String) row
233 .get(COLUMN_TP_DST));
234 }
235
236 else if (key.equals(COLUMN_WILDCARD_DPID)) {
237 r.wildcard_dpid = Boolean.parseBoolean((String) row
238 .get(COLUMN_WILDCARD_DPID));
239 }
240
241 else if (key.equals(COLUMN_WILDCARD_IN_PORT)) {
242 r.wildcard_in_port = Boolean
243 .parseBoolean((String) row
244 .get(COLUMN_WILDCARD_IN_PORT));
245 }
246
247 else if (key.equals(COLUMN_WILDCARD_DL_SRC)) {
248 r.wildcard_dl_src = Boolean
249 .parseBoolean((String) row
250 .get(COLUMN_WILDCARD_DL_SRC));
251 }
252
253 else if (key.equals(COLUMN_WILDCARD_DL_DST)) {
254 r.wildcard_dl_dst = Boolean
255 .parseBoolean((String) row
256 .get(COLUMN_WILDCARD_DL_DST));
257 }
258
259 else if (key.equals(COLUMN_WILDCARD_DL_TYPE)) {
260 r.wildcard_dl_type = Boolean
261 .parseBoolean((String) row
262 .get(COLUMN_WILDCARD_DL_TYPE));
263 }
264
265 else if (key.equals(COLUMN_WILDCARD_NW_SRC)) {
266 r.wildcard_nw_src = Boolean
267 .parseBoolean((String) row
268 .get(COLUMN_WILDCARD_NW_SRC));
269 }
270
271 else if (key.equals(COLUMN_WILDCARD_NW_DST)) {
272 r.wildcard_nw_dst = Boolean
273 .parseBoolean((String) row
274 .get(COLUMN_WILDCARD_NW_DST));
275 }
276
277 else if (key.equals(COLUMN_WILDCARD_NW_PROTO)) {
278 r.wildcard_nw_proto = Boolean
279 .parseBoolean((String) row
280 .get(COLUMN_WILDCARD_NW_PROTO));
281 }
282
283 else if (key.equals(COLUMN_PRIORITY)) {
284 r.priority = Integer.parseInt((String) row
285 .get(COLUMN_PRIORITY));
286 }
287
288 else if (key.equals(COLUMN_ACTION)) {
289 int tmp = Integer.parseInt((String) row.get(COLUMN_ACTION));
290 if (tmp == FirewallRule.FirewallAction.DENY.ordinal())
291 r.action = FirewallRule.FirewallAction.DENY;
292 else if (tmp == FirewallRule.FirewallAction.ALLOW.ordinal())
293 r.action = FirewallRule.FirewallAction.ALLOW;
294 else {
295 r.action = null;
296 logger.error("action not recognized");
297 }
298 }
299 }
300 } catch (ClassCastException e) {
301 logger.error(
302 "skipping rule {} with bad data : "
303 + e.getMessage(), r.ruleid);
304 }
305 if (r.action != null)
306 l.add(r);
307 }
308 } catch (StorageException e) {
309 logger.error("failed to access storage: {}", e.getMessage());
310 // if the table doesn't exist, then wait to populate later via
311 // setStorageSource()
312 }
313
314 // now, sort the list based on priorities
315 Collections.sort(l);
316
317 return l;
318 }
319
320 @Override
321 public void init(FloodlightModuleContext context)
322 throws FloodlightModuleException {
323 floodlightProvider = context
324 .getServiceImpl(IFloodlightProviderService.class);
325 storageSource = context.getServiceImpl(IStorageSourceService.class);
326 restApi = context.getServiceImpl(IRestApiService.class);
327 rules = new ArrayList<FirewallRule>();
328 logger = LoggerFactory.getLogger(Firewall.class);
329
330 // start disabled
331 enabled = false;
332 }
333
334 @Override
335 public void startUp(FloodlightModuleContext context) {
336 // register REST interface
337 restApi.addRestletRoutable(new FirewallWebRoutable());
338
339 // always place firewall in pipeline at bootup
340 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
341
342 // storage, create table and read rules
343 storageSource.createTable(TABLE_NAME, null);
344 storageSource.setTablePrimaryKeyName(TABLE_NAME, COLUMN_RULEID);
345 synchronized (rules) {
346 this.rules = readRulesFromStorage();
347 }
348 }
349
350 @Override
351 public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
352 if (!this.enabled)
353 return Command.CONTINUE;
354
355 switch (msg.getType()) {
356 case PACKET_IN:
357 IRoutingDecision decision = null;
358 if (cntx != null) {
359 decision = IRoutingDecision.rtStore.get(cntx,
360 IRoutingDecision.CONTEXT_DECISION);
361
362 return this.processPacketInMessage(sw, (OFPacketIn) msg,
363 decision, cntx);
364 }
365 break;
366 default:
367 break;
368 }
369
370 return Command.CONTINUE;
371 }
372
373 @Override
374 public void enableFirewall(boolean enabled) {
375 logger.info("Setting firewall to {}", enabled);
376 this.enabled = enabled;
377 }
378
379 @Override
380 public List<FirewallRule> getRules() {
381 return this.rules;
382 }
383
384 // Only used to serve REST GET
385 // Similar to readRulesFromStorage(), which actually checks and stores
386 // record into FirewallRule list
387 @Override
388 public List<Map<String, Object>> getStorageRules() {
389 ArrayList<Map<String, Object>> l = new ArrayList<Map<String, Object>>();
390 try {
391 // null1=no predicate, null2=no ordering
392 IResultSet resultSet = storageSource.executeQuery(TABLE_NAME,
393 ColumnNames, null, null);
394 for (Iterator<IResultSet> it = resultSet.iterator(); it.hasNext();) {
395 l.add(it.next().getRow());
396 }
397 } catch (StorageException e) {
398 logger.error("failed to access storage: {}", e.getMessage());
399 // if the table doesn't exist, then wait to populate later via
400 // setStorageSource()
401 }
402 return l;
403 }
404
405 @Override
406 public String getSubnetMask() {
407 return IPv4.fromIPv4Address(this.subnet_mask);
408 }
409
410 @Override
411 public void setSubnetMask(String newMask) {
412 if (newMask.trim().isEmpty())
413 return;
414 this.subnet_mask = IPv4.toIPv4Address(newMask.trim());
415 }
416
417 @Override
418 public synchronized void addRule(FirewallRule rule) {
419
420 // generate random ruleid for each newly created rule
421 // may want to return to caller if useful
422 // may want to check conflict
423 rule.ruleid = rule.genID();
424
425 int i = 0;
426 // locate the position of the new rule in the sorted arraylist
427 for (i = 0; i < this.rules.size(); i++) {
428 if (this.rules.get(i).priority >= rule.priority)
429 break;
430 }
431 // now, add rule to the list
432 if (i <= this.rules.size()) {
433 this.rules.add(i, rule);
434 } else {
435 this.rules.add(rule);
436 }
437 // add rule to database
438 Map<String, Object> entry = new HashMap<String, Object>();
439 entry.put(COLUMN_RULEID, Integer.toString(rule.ruleid));
440 entry.put(COLUMN_DPID, Long.toString(rule.dpid));
441 entry.put(COLUMN_IN_PORT, Short.toString(rule.in_port));
442 entry.put(COLUMN_DL_SRC, Long.toString(rule.dl_src));
443 entry.put(COLUMN_DL_DST, Long.toString(rule.dl_dst));
444 entry.put(COLUMN_DL_TYPE, Short.toString(rule.dl_type));
445 entry.put(COLUMN_NW_SRC_PREFIX, Integer.toString(rule.nw_src_prefix));
446 entry.put(COLUMN_NW_SRC_MASKBITS, Integer.toString(rule.nw_src_maskbits));
447 entry.put(COLUMN_NW_DST_PREFIX, Integer.toString(rule.nw_dst_prefix));
448 entry.put(COLUMN_NW_DST_MASKBITS, Integer.toString(rule.nw_dst_maskbits));
449 entry.put(COLUMN_NW_PROTO, Short.toString(rule.nw_proto));
450 entry.put(COLUMN_TP_SRC, Integer.toString(rule.tp_src));
451 entry.put(COLUMN_TP_DST, Integer.toString(rule.tp_dst));
452 entry.put(COLUMN_WILDCARD_DPID,
453 Boolean.toString(rule.wildcard_dpid));
454 entry.put(COLUMN_WILDCARD_IN_PORT,
455 Boolean.toString(rule.wildcard_in_port));
456 entry.put(COLUMN_WILDCARD_DL_SRC,
457 Boolean.toString(rule.wildcard_dl_src));
458 entry.put(COLUMN_WILDCARD_DL_DST,
459 Boolean.toString(rule.wildcard_dl_dst));
460 entry.put(COLUMN_WILDCARD_DL_TYPE,
461 Boolean.toString(rule.wildcard_dl_type));
462 entry.put(COLUMN_WILDCARD_NW_SRC,
463 Boolean.toString(rule.wildcard_nw_src));
464 entry.put(COLUMN_WILDCARD_NW_DST,
465 Boolean.toString(rule.wildcard_nw_dst));
466 entry.put(COLUMN_WILDCARD_NW_PROTO,
467 Boolean.toString(rule.wildcard_nw_proto));
468 entry.put(COLUMN_WILDCARD_TP_SRC,
469 Boolean.toString(rule.wildcard_tp_src));
470 entry.put(COLUMN_WILDCARD_TP_DST,
471 Boolean.toString(rule.wildcard_tp_dst));
472 entry.put(COLUMN_PRIORITY, Integer.toString(rule.priority));
473 entry.put(COLUMN_ACTION, Integer.toString(rule.action.ordinal()));
474 storageSource.insertRow(TABLE_NAME, entry);
475 }
476
477 @Override
478 public synchronized void deleteRule(int ruleid) {
479 Iterator<FirewallRule> iter = this.rules.iterator();
480 while (iter.hasNext()) {
481 FirewallRule r = iter.next();
482 if (r.ruleid == ruleid) {
483 // found the rule, now remove it
484 iter.remove();
485 break;
486 }
487 }
488 // delete from database
489 storageSource.deleteRow(TABLE_NAME, Integer.toString(ruleid));
490 }
491
492 /**
493 * Iterates over the firewall rules and tries to match them with the
494 * incoming packet (flow). Uses the FirewallRule class's matchWithFlow
495 * method to perform matching. It maintains a pair of wildcards (allow and
496 * deny) which are assigned later to the firewall's decision, where 'allow'
497 * wildcards are applied if the matched rule turns out to be an ALLOW rule
498 * and 'deny' wildcards are applied otherwise. Wildcards are applied to
499 * firewall decision to optimize flows in the switch, ensuring least number
500 * of flows per firewall rule. So, if a particular field is not "ANY" (i.e.
501 * not wildcarded) in a higher priority rule, then if a lower priority rule
502 * matches the packet and wildcards it, it can't be wildcarded in the
503 * switch's flow entry, because otherwise some packets matching the higher
504 * priority rule might escape the firewall. The reason for keeping different
505 * two different wildcards is that if a field is not wildcarded in a higher
506 * priority allow rule, the same field shouldn't be wildcarded for packets
507 * matching the lower priority deny rule (non-wildcarded fields in higher
508 * priority rules override the wildcarding of those fields in lower priority
509 * rules of the opposite type). So, to ensure that wildcards are
510 * appropriately set for different types of rules (allow vs. deny), separate
511 * wildcards are maintained. Iteration is performed on the sorted list of
512 * rules (sorted in decreasing order of priority).
513 *
514 * @param sw
515 * the switch instance
516 * @param pi
517 * the incoming packet data structure
518 * @param cntx
519 * the floodlight context
520 * @return an instance of RuleWildcardsPair that specify rule that matches
521 * and the wildcards for the firewall decision
522 */
523 protected RuleWildcardsPair matchWithRule(IOFSwitch sw, OFPacketIn pi,
524 FloodlightContext cntx) {
525 FirewallRule matched_rule = null;
526 Ethernet eth = IFloodlightProviderService.bcStore.get(cntx,
527 IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
528 WildcardsPair wildcards = new WildcardsPair();
529
530 synchronized (rules) {
531 Iterator<FirewallRule> iter = this.rules.iterator();
532 FirewallRule rule = null;
533 // iterate through list to find a matching firewall rule
534 while (iter.hasNext()) {
535 // get next rule from list
536 rule = iter.next();
537
538 // check if rule matches
539 if (rule.matchesFlow(sw.getId(), pi.getInPort(), eth, wildcards) == true) {
540 matched_rule = rule;
541 break;
542 }
543 }
544 }
545
546 // make a pair of rule and wildcards, then return it
547 RuleWildcardsPair ret = new RuleWildcardsPair();
548 ret.rule = matched_rule;
549 if (matched_rule == null || matched_rule.action == FirewallRule.FirewallAction.DENY) {
550 ret.wildcards = wildcards.drop;
551 } else {
552 ret.wildcards = wildcards.allow;
553 }
554 return ret;
555 }
556
557 /**
558 * Checks whether an IP address is a broadcast address or not (determines
559 * using subnet mask)
560 *
561 * @param IPAddress
562 * the IP address to check
563 * @return true if it is a broadcast address, false otherwise
564 */
565 protected boolean IPIsBroadcast(int IPAddress) {
566 // inverted subnet mask
567 int inv_subnet_mask = ~this.subnet_mask;
568 return ((IPAddress & inv_subnet_mask) == inv_subnet_mask);
569 }
570
571 public Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi,
572 IRoutingDecision decision, FloodlightContext cntx) {
573 Ethernet eth = IFloodlightProviderService.bcStore.get(cntx,
574 IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
575
576 // Allowing L2 broadcast + ARP broadcast request (also deny malformed
577 // broadcasts -> L2 broadcast + L3 unicast)
578 if (eth.isBroadcast() == true) {
579 boolean allowBroadcast = true;
580 // the case to determine if we have L2 broadcast + L3 unicast
581 // don't allow this broadcast packet if such is the case (malformed
582 // packet)
583 if (eth.getEtherType() == Ethernet.TYPE_IPv4
584 && this.IPIsBroadcast(((IPv4) eth.getPayload())
585 .getDestinationAddress()) == false) {
586 allowBroadcast = false;
587 }
588 if (allowBroadcast == true) {
589 if (logger.isTraceEnabled())
590 logger.trace("Allowing broadcast traffic for PacketIn={}",
591 pi);
592
593 decision = new RoutingDecision(sw.getId(), pi.getInPort()
594 , IDeviceService.fcStore.
595 get(cntx, IDeviceService.CONTEXT_SRC_DEVICE),
596 IRoutingDecision.RoutingAction.MULTICAST);
597 decision.addToContext(cntx);
598 } else {
599 if (logger.isTraceEnabled())
600 logger.trace(
601 "Blocking malformed broadcast traffic for PacketIn={}",
602 pi);
603
604 decision = new RoutingDecision(sw.getId(), pi.getInPort()
605 , IDeviceService.fcStore.
606 get(cntx, IDeviceService.CONTEXT_SRC_DEVICE),
607 IRoutingDecision.RoutingAction.DROP);
608 decision.addToContext(cntx);
609 }
610 return Command.CONTINUE;
611 }
612 /*
613 * ARP response (unicast) can be let through without filtering through
614 * rules by uncommenting the code below
615 */
616 /*
617 * else if (eth.getEtherType() == Ethernet.TYPE_ARP) {
618 * logger.info("allowing ARP traffic"); decision = new
619 * FirewallDecision(IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD);
620 * decision.addToContext(cntx); return Command.CONTINUE; }
621 */
622
623 // check if we have a matching rule for this packet/flow
624 // and no decision is taken yet
625 if (decision == null) {
626 RuleWildcardsPair match_ret = this.matchWithRule(sw, pi, cntx);
627 FirewallRule rule = match_ret.rule;
628
629 if (rule == null || rule.action == FirewallRule.FirewallAction.DENY) {
630 decision = new RoutingDecision(sw.getId(), pi.getInPort()
631 , IDeviceService.fcStore.
632 get(cntx, IDeviceService.CONTEXT_SRC_DEVICE),
633 IRoutingDecision.RoutingAction.DROP);
634 decision.setWildcards(match_ret.wildcards);
635 decision.addToContext(cntx);
636 if (logger.isTraceEnabled()) {
637 if (rule == null)
638 logger.trace(
639 "No firewall rule found for PacketIn={}, blocking flow",
640 pi);
641 else if (rule.action == FirewallRule.FirewallAction.DENY) {
642 logger.trace("Deny rule={} match for PacketIn={}",
643 rule, pi);
644 }
645 }
646 } else {
647 decision = new RoutingDecision(sw.getId(), pi.getInPort()
648 , IDeviceService.fcStore.
649 get(cntx, IDeviceService.CONTEXT_SRC_DEVICE),
650 IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD);
651 decision.setWildcards(match_ret.wildcards);
652 decision.addToContext(cntx);
653 if (logger.isTraceEnabled())
654 logger.trace("Allow rule={} match for PacketIn={}", rule,
655 pi);
656 }
657 }
658
659 return Command.CONTINUE;
660 }
661
662 @Override
663 public boolean isEnabled() {
664 return enabled;
665 }
666
667}