Fix for ONOS-4803. Issue with of error msg parsing by flood light.
Change-Id: I43b8ce5ab21000670359c76cc24d9a457ff6e125 (cherry picked from commit d258135a)
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,21 +541,102 @@ public class OpenFlowRuleProvider extends AbstractProvider | ... | @@ -531,21 +541,102 @@ 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 | + } | ||
| 546 | } | 576 | } |
| 547 | } | 577 | } |
| 548 | 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()); | ||
| 638 | + } | ||
| 639 | + | ||
| 549 | @Override | 640 | @Override |
| 550 | public void receivedRoleReply(Dpid dpid, RoleState requested, | 641 | public void receivedRoleReply(Dpid dpid, RoleState requested, |
| 551 | RoleState response) { | 642 | RoleState response) { |
| ... | @@ -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