Committed by
Jonathan Hart
Fix for ONOS-4803. Issue with of error msg parsing by flood light.
Change-Id: I43b8ce5ab21000670359c76cc24d9a457ff6e125
Showing
1 changed file
with
98 additions
and
7 deletions
... | @@ -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 | ... | ... |
-
Please register or login to post a comment