Prince Pereira
Committed by Jonathan Hart

Fix for ONOS-4803. Issue with of error msg parsing by flood light.

Change-Id: I43b8ce5ab21000670359c76cc24d9a457ff6e125
...@@ -31,6 +31,8 @@ import org.apache.felix.scr.annotations.Modified; ...@@ -31,6 +31,8 @@ import org.apache.felix.scr.annotations.Modified;
31 import org.apache.felix.scr.annotations.Property; 31 import org.apache.felix.scr.annotations.Property;
32 import org.apache.felix.scr.annotations.Reference; 32 import org.apache.felix.scr.annotations.Reference;
33 import org.apache.felix.scr.annotations.ReferenceCardinality; 33 import org.apache.felix.scr.annotations.ReferenceCardinality;
34 +import org.jboss.netty.buffer.ChannelBuffer;
35 +import org.jboss.netty.buffer.ChannelBuffers;
34 import org.onosproject.cfg.ComponentConfigService; 36 import org.onosproject.cfg.ComponentConfigService;
35 import org.onosproject.core.ApplicationId; 37 import org.onosproject.core.ApplicationId;
36 import org.onosproject.net.DeviceId; 38 import org.onosproject.net.DeviceId;
...@@ -70,11 +72,15 @@ import org.projectfloodlight.openflow.protocol.OFStatsReply; ...@@ -70,11 +72,15 @@ import org.projectfloodlight.openflow.protocol.OFStatsReply;
70 import org.projectfloodlight.openflow.protocol.OFStatsType; 72 import org.projectfloodlight.openflow.protocol.OFStatsType;
71 import org.projectfloodlight.openflow.protocol.OFTableStatsEntry; 73 import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
72 import org.projectfloodlight.openflow.protocol.OFTableStatsReply; 74 import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
75 +import org.projectfloodlight.openflow.protocol.OFType;
76 +import org.projectfloodlight.openflow.protocol.OFVersion;
73 import org.projectfloodlight.openflow.protocol.errormsg.OFBadActionErrorMsg; 77 import org.projectfloodlight.openflow.protocol.errormsg.OFBadActionErrorMsg;
74 import org.projectfloodlight.openflow.protocol.errormsg.OFBadInstructionErrorMsg; 78 import org.projectfloodlight.openflow.protocol.errormsg.OFBadInstructionErrorMsg;
75 import org.projectfloodlight.openflow.protocol.errormsg.OFBadMatchErrorMsg; 79 import org.projectfloodlight.openflow.protocol.errormsg.OFBadMatchErrorMsg;
76 import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg; 80 import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
77 import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg; 81 import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
82 +import org.projectfloodlight.openflow.types.U16;
83 +import org.projectfloodlight.openflow.types.U64;
78 import org.slf4j.Logger; 84 import org.slf4j.Logger;
79 85
80 import java.util.Collections; 86 import java.util.Collections;
...@@ -116,11 +122,14 @@ public class OpenFlowRuleProvider extends AbstractProvider ...@@ -116,11 +122,14 @@ public class OpenFlowRuleProvider extends AbstractProvider
116 protected DriverService driverService; 122 protected DriverService driverService;
117 123
118 private static final int DEFAULT_POLL_FREQUENCY = 5; 124 private static final int DEFAULT_POLL_FREQUENCY = 5;
125 + private static final int MIN_EXPECTED_BYTE_LEN = 56;
126 + private static final int SKIP_BYTES = 4;
127 + private static final boolean DEFAULT_ADAPTIVE_FLOW_SAMPLING = false;
128 +
119 @Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY, 129 @Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY,
120 label = "Frequency (in seconds) for polling flow statistics") 130 label = "Frequency (in seconds) for polling flow statistics")
121 private int flowPollFrequency = DEFAULT_POLL_FREQUENCY; 131 private int flowPollFrequency = DEFAULT_POLL_FREQUENCY;
122 132
123 - private static final boolean DEFAULT_ADAPTIVE_FLOW_SAMPLING = false;
124 @Property(name = "adaptiveFlowSampling", boolValue = DEFAULT_ADAPTIVE_FLOW_SAMPLING, 133 @Property(name = "adaptiveFlowSampling", boolValue = DEFAULT_ADAPTIVE_FLOW_SAMPLING,
125 label = "Adaptive Flow Sampling is on or off") 134 label = "Adaptive Flow Sampling is on or off")
126 private boolean adaptiveFlowSampling = DEFAULT_ADAPTIVE_FLOW_SAMPLING; 135 private boolean adaptiveFlowSampling = DEFAULT_ADAPTIVE_FLOW_SAMPLING;
...@@ -500,6 +509,7 @@ public class OpenFlowRuleProvider extends AbstractProvider ...@@ -500,6 +509,7 @@ public class OpenFlowRuleProvider extends AbstractProvider
500 } 509 }
501 510
502 private void handleErrorMsg(DeviceId deviceId, OFMessage msg) { 511 private void handleErrorMsg(DeviceId deviceId, OFMessage msg) {
512 + InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
503 OFErrorMsg error = (OFErrorMsg) msg; 513 OFErrorMsg error = (OFErrorMsg) msg;
504 OFMessage ofMessage = null; 514 OFMessage ofMessage = null;
505 switch (error.getErrType()) { 515 switch (error.getErrType()) {
...@@ -531,19 +541,100 @@ public class OpenFlowRuleProvider extends AbstractProvider ...@@ -531,19 +541,100 @@ public class OpenFlowRuleProvider extends AbstractProvider
531 // Do nothing. 541 // Do nothing.
532 return; 542 return;
533 } 543 }
544 +
534 if (ofMessage != null) { 545 if (ofMessage != null) {
535 - InternalCacheEntry entry = 546 +
536 - pendingBatches.getIfPresent(msg.getXid());
537 if (entry != null) { 547 if (entry != null) {
538 OFFlowMod ofFlowMod = (OFFlowMod) ofMessage; 548 OFFlowMod ofFlowMod = (OFFlowMod) ofMessage;
539 entry.appendFailure(new FlowEntryBuilder(deviceId, ofFlowMod, driverService).build()); 549 entry.appendFailure(new FlowEntryBuilder(deviceId, ofFlowMod, driverService).build());
540 } else { 550 } else {
541 log.error("No matching batch for this error: {}", error); 551 log.error("No matching batch for this error: {}", error);
542 } 552 }
553 +
543 } else { 554 } else {
544 - log.error("Flow installation failed but switch didn't" 555 +
545 - + " tell us which one."); 556 + U64 cookieId = readCookieIdFromOFErrorMsg(error, msg.getVersion());
557 +
558 + if (cookieId != null) {
559 + long flowId = cookieId.getValue();
560 +
561 + if (entry != null) {
562 + for (FlowRuleBatchEntry fbEntry : entry.operation.getOperations()) {
563 + if (fbEntry.target().id().value() == flowId) {
564 + entry.appendFailure(fbEntry.target());
565 + break;
566 + }
567 + }
568 + } else {
569 + log.error("No matching batch for this error: {}", error);
570 + }
571 +
572 + } else {
573 + log.error("Flow installation failed but switch " +
574 + "didn't tell us which one.");
575 + }
576 + }
546 } 577 }
578 +
579 + /**
580 + * Reading cookieId from OFErrorMsg.
581 + *
582 + * Loxigen OpenFlow API failed in parsing error messages because of
583 + * 64 byte data truncation based on OpenFlow specs. The method written
584 + * is a workaround to extract the cookieId from the packet till the
585 + * issue is resolved in Loxigen OpenFlow code.
586 + * Ref: https://groups.google.com/a/onosproject.org/forum/#!topic
587 + * /onos-dev/_KwlHZDllLE
588 + *
589 + * @param msg OF error message
590 + * @param ofVersion Openflow version
591 + * @return cookieId
592 + */
593 + private U64 readCookieIdFromOFErrorMsg(OFErrorMsg msg,
594 + OFVersion ofVersion) {
595 +
596 + if (ofVersion.wireVersion < OFVersion.OF_13.wireVersion) {
597 + log.debug("Unhandled error msg with OF version {} " +
598 + "which is less than {}",
599 + ofVersion, OFVersion.OF_13);
600 + return null;
601 + }
602 +
603 + ChannelBuffer bb = ChannelBuffers.wrappedBuffer(
604 + msg.getData().getData());
605 +
606 + if (bb.readableBytes() < MIN_EXPECTED_BYTE_LEN) {
607 + log.debug("Wrong length: Expected to be >= {}, was: {}",
608 + MIN_EXPECTED_BYTE_LEN, bb.readableBytes());
609 + return null;
610 + }
611 +
612 + byte ofVer = bb.readByte();
613 +
614 + if (ofVer != ofVersion.wireVersion) {
615 + log.debug("Wrong version: Expected={}, got={}",
616 + ofVersion.wireVersion, ofVer);
617 + return null;
618 + }
619 +
620 + byte type = bb.readByte();
621 +
622 + if (type != OFType.FLOW_MOD.ordinal()) {
623 + log.debug("Wrong type: Expected={}, got={}",
624 + OFType.FLOW_MOD.ordinal(), type);
625 + return null;
626 + }
627 +
628 + int length = U16.f(bb.readShort());
629 +
630 + if (length < MIN_EXPECTED_BYTE_LEN) {
631 + log.debug("Wrong length: Expected to be >= {}, was: {}",
632 + MIN_EXPECTED_BYTE_LEN, length);
633 + return null;
634 + }
635 +
636 + bb.skipBytes(SKIP_BYTES);
637 + return U64.ofRaw(bb.readLong());
547 } 638 }
548 639
549 @Override 640 @Override
...@@ -565,8 +656,8 @@ public class OpenFlowRuleProvider extends AbstractProvider ...@@ -565,8 +656,8 @@ public class OpenFlowRuleProvider extends AbstractProvider
565 656
566 synchronized (afsc) { 657 synchronized (afsc) {
567 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) { 658 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
568 - log.debug("OpenFlowRuleProvider:pushFlowMetrics, flowMissingXid={}, " 659 + log.debug("OpenFlowRuleProvider:pushFlowMetrics, flowMissingXid={}, " +
569 - + "OFFlowStatsReply Xid={}, for {}", 660 + "OFFlowStatsReply Xid={}, for {}",
570 afsc.getFlowMissingXid(), replies.getXid(), dpid); 661 afsc.getFlowMissingXid(), replies.getXid(), dpid);
571 } 662 }
572 663
......