16 package org.openkilda.floodlight.switchmanager;
18 import static java.util.Arrays.asList;
19 import static java.util.Collections.emptyList;
20 import static java.util.Collections.singletonList;
23 import static org.projectfloodlight.openflow.protocol.OFVersion.OF_12;
24 import static org.projectfloodlight.openflow.protocol.OFVersion.OF_13;
25 import static org.projectfloodlight.openflow.protocol.OFVersion.OF_15;
43 import com.google.common.collect.ImmutableSet;
44 import com.google.common.util.concurrent.ListenableFuture;
45 import net.floodlightcontroller.core.FloodlightContext;
46 import net.floodlightcontroller.core.IFloodlightProviderService;
47 import net.floodlightcontroller.core.IOFMessageListener;
48 import net.floodlightcontroller.core.IOFSwitch;
49 import net.floodlightcontroller.core.PortChangeType;
50 import net.floodlightcontroller.core.internal.IOFSwitchService;
51 import net.floodlightcontroller.core.module.FloodlightModuleContext;
52 import net.floodlightcontroller.core.module.FloodlightModuleException;
53 import net.floodlightcontroller.core.module.IFloodlightModule;
54 import net.floodlightcontroller.core.module.IFloodlightService;
55 import net.floodlightcontroller.restserver.IRestApiService;
56 import net.floodlightcontroller.util.FlowModUtils;
57 import org.projectfloodlight.openflow.protocol.OFBarrierReply;
58 import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
59 import org.projectfloodlight.openflow.protocol.OFErrorMsg;
60 import org.projectfloodlight.openflow.protocol.OFFactory;
61 import org.projectfloodlight.openflow.protocol.OFFlowDelete;
62 import org.projectfloodlight.openflow.protocol.OFFlowMod;
63 import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
64 import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
65 import org.projectfloodlight.openflow.protocol.OFFlowStatsRequest;
66 import org.projectfloodlight.openflow.protocol.OFLegacyMeterBandDrop;
67 import org.projectfloodlight.openflow.protocol.OFLegacyMeterFlags;
68 import org.projectfloodlight.openflow.protocol.OFLegacyMeterMod;
69 import org.projectfloodlight.openflow.protocol.OFLegacyMeterModCommand;
70 import org.projectfloodlight.openflow.protocol.OFMessage;
71 import org.projectfloodlight.openflow.protocol.OFMeterConfigStatsReply;
72 import org.projectfloodlight.openflow.protocol.OFMeterConfigStatsRequest;
73 import org.projectfloodlight.openflow.protocol.OFMeterFlags;
74 import org.projectfloodlight.openflow.protocol.OFMeterMod;
75 import org.projectfloodlight.openflow.protocol.OFMeterModCommand;
76 import org.projectfloodlight.openflow.protocol.OFPortConfig;
77 import org.projectfloodlight.openflow.protocol.OFPortDesc;
78 import org.projectfloodlight.openflow.protocol.OFPortMod;
79 import org.projectfloodlight.openflow.protocol.OFType;
80 import org.projectfloodlight.openflow.protocol.action.OFAction;
81 import org.projectfloodlight.openflow.protocol.action.OFActions;
82 import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
83 import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
84 import org.projectfloodlight.openflow.protocol.instruction.OFInstructionMeter;
85 import org.projectfloodlight.openflow.protocol.match.Match;
86 import org.projectfloodlight.openflow.protocol.match.Match.Builder;
87 import org.projectfloodlight.openflow.protocol.match.MatchField;
88 import org.projectfloodlight.openflow.protocol.meterband.OFMeterBandDrop;
89 import org.projectfloodlight.openflow.protocol.oxm.OFOxms;
90 import org.projectfloodlight.openflow.types.DatapathId;
91 import org.projectfloodlight.openflow.types.EthType;
92 import org.projectfloodlight.openflow.types.MacAddress;
93 import org.projectfloodlight.openflow.types.OFBufferId;
94 import org.projectfloodlight.openflow.types.OFGroup;
95 import org.projectfloodlight.openflow.types.OFPort;
96 import org.projectfloodlight.openflow.types.OFVlanVidMatch;
97 import org.projectfloodlight.openflow.types.U64;
98 import org.slf4j.Logger;
99 import org.slf4j.LoggerFactory;
101 import java.util.ArrayList;
102 import java.util.Arrays;
103 import java.util.Collection;
104 import java.util.HashMap;
105 import java.util.HashSet;
106 import java.util.List;
107 import java.util.Map;
108 import java.util.Optional;
109 import java.util.Set;
110 import java.util.concurrent.ExecutionException;
111 import java.util.concurrent.Future;
112 import java.util.concurrent.TimeUnit;
113 import java.util.concurrent.TimeoutException;
114 import java.util.stream.Collectors;
115 import java.util.stream.Stream;
121 private static final Logger logger = LoggerFactory.getLogger(
SwitchManager.class);
129 static final U64 NON_SYSTEM_MASK = U64.of(0x80000000FFFFFFFFL);
137 private static short OF10_VLAN_MASK = 0x0FFF;
139 private IFloodlightProviderService floodlightProvider;
140 private IOFSwitchService ofSwitchService;
141 private IRestApiService restApiService;
145 private String topoDiscoTopic;
156 private static OFInstructionApplyActions buildInstructionApplyActions(OFFactory ofFactory,
157 List<OFAction> actionList) {
158 return ofFactory.instructions().applyActions(actionList).createBuilder().build();
168 private static OFAction legacyMeterAction(
final OFFactory ofFactory,
final long meterId) {
169 return ofFactory.actions().buildNiciraLegacyMeter().setMeterId(meterId).build();
177 Collection<Class<? extends IFloodlightService>> services =
new ArrayList<>();
186 public Map<Class<? extends IFloodlightService>, IFloodlightService>
getServiceImpls() {
187 Map<Class<? extends IFloodlightService>, IFloodlightService> map =
new HashMap<>();
197 Collection<Class<? extends IFloodlightService>> services =
new ArrayList<>(3);
198 services.add(IFloodlightProviderService.class);
199 services.add(IOFSwitchService.class);
200 services.add(IRestApiService.class);
208 public void init(FloodlightModuleContext context)
throws FloodlightModuleException {
209 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
210 ofSwitchService = context.getServiceImpl(IOFSwitchService.class);
211 restApiService = context.getServiceImpl(IRestApiService.class);
218 String connectModeProperty = provider.getConfiguration(
SwitchManagerConfig.class).getConnectMode();
221 }
catch (Exception e) {
222 logger.error(
"CONFIG EXCEPTION: connect-mode could not be set to {}, defaulting to AUTO",
223 connectModeProperty);
233 public void startUp(FloodlightModuleContext context)
throws FloodlightModuleException {
236 floodlightProvider.addOFMessageListener(OFType.ERROR,
this);
244 public Command
receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
245 logger.debug(
"OF_ERROR: {}", msg);
247 if (OFType.ERROR.equals(msg.getType())) {
255 return Command.CONTINUE;
263 return "KildaSwitchManager";
273 logger.trace(
"isCallbackOrderingPrereq for {} : {}",
type,
name);
282 logger.trace(
"isCallbackOrderingPostreq for {} : {}",
type,
name);
292 this.connectMode = mode;
294 return this.connectMode;
312 final DatapathId dpid,
final String flowId,
313 final Long cookie,
final int inputPort,
final int outputPort,
314 final int inputVlanId,
final int transitVlanId,
316 List<OFAction> actionList =
new ArrayList<>();
317 IOFSwitch sw = lookupSwitch(dpid);
318 OFFactory ofFactory = sw.getOFFactory();
322 OFInstructionMeter meter = null;
323 if (meterId != 0L && !
OVS_MANUFACTURER.equals(sw.getSwitchDescription().getManufacturerDescription())) {
324 if (ofFactory.getVersion().compareTo(OF_12) <= 0) {
325 actionList.add(legacyMeterAction(ofFactory, meterId));
326 }
else if (ofFactory.getVersion().compareTo(OF_15) == 0) {
327 actionList.add(ofFactory.actions().buildMeter().setMeterId(meterId).build());
329 meter = ofFactory.instructions().buildMeter().setMeterId(meterId).build();
334 actionList.addAll(inputVlanTypeToOfActionList(ofFactory, transitVlanId, outputVlanType));
337 actionList.add(actionSetOutputPort(ofFactory, outputPort));
340 OFInstructionApplyActions actions = buildInstructionApplyActions(ofFactory, actionList);
343 Match match = matchFlow(ofFactory, inputPort, inputVlanId);
346 OFFlowMod flowMod = buildFlowMod(ofFactory, match, meter, actions,
349 return pushFlow(sw,
"--InstallIngressFlow--", flowMod);
357 final DatapathId dpid, String flowId,
final Long cookie,
358 final int inputPort,
final int outputPort,
359 final int transitVlanId,
final int outputVlanId,
361 List<OFAction> actionList =
new ArrayList<>();
362 IOFSwitch sw = lookupSwitch(dpid);
363 OFFactory ofFactory = sw.getOFFactory();
366 Match match = matchFlow(ofFactory, inputPort, transitVlanId);
369 actionList.addAll(outputVlanTypeToOfActionList(ofFactory, outputVlanId, outputVlanType));
372 actionList.add(actionSetOutputPort(ofFactory, outputPort));
375 OFInstructionApplyActions actions = buildInstructionApplyActions(ofFactory, actionList);
378 OFFlowMod flowMod = buildFlowMod(ofFactory, match, null, actions,
381 return pushFlow(sw,
"--InstallEgressFlow--", flowMod);
389 final DatapathId dpid,
final String flowId,
390 final Long cookie,
final int inputPort,
final int outputPort,
392 List<OFAction> actionList =
new ArrayList<>();
393 IOFSwitch sw = lookupSwitch(dpid);
394 OFFactory ofFactory = sw.getOFFactory();
397 Match match = matchFlow(ofFactory, inputPort, transitVlanId);
400 actionList.add(actionSetOutputPort(ofFactory, outputPort));
403 OFInstructionApplyActions actions = buildInstructionApplyActions(ofFactory, actionList);
406 OFFlowMod flowMod = buildFlowMod(ofFactory, match, null, actions,
409 return pushFlow(sw, flowId, flowMod);
417 final DatapathId dpid,
final String flowId,
418 final Long cookie,
final int inputPort,
419 final int outputPort,
final int inputVlanId,
420 final int outputVlanId,
426 List<OFAction> actionList =
new ArrayList<>();
427 IOFSwitch sw = lookupSwitch(dpid);
428 OFFactory ofFactory = sw.getOFFactory();
432 OFInstructionMeter meter = null;
433 if (meterId != 0L && !
OVS_MANUFACTURER.equals(sw.getSwitchDescription().getManufacturerDescription())) {
434 if (ofFactory.getVersion().compareTo(OF_12) <= 0) {
435 actionList.add(legacyMeterAction(ofFactory, meterId));
436 }
else if (ofFactory.getVersion().compareTo(OF_15) == 0) {
437 actionList.add(ofFactory.actions().buildMeter().setMeterId(meterId).build());
439 meter = ofFactory.instructions().buildMeter().setMeterId(meterId).build();
444 actionList.addAll(pushSchemeOutputVlanTypeToOfActionList(ofFactory, outputVlanId, outputVlanType));
446 actionList.add(actionSetOutputPort(ofFactory, outputPort));
449 OFInstructionApplyActions actions = buildInstructionApplyActions(ofFactory, actionList);
452 Match match = matchFlow(ofFactory, inputPort, inputVlanId);
455 OFFlowMod flowMod = buildFlowMod(ofFactory, match, meter, actions,
458 pushFlow(sw, flowId, flowMod);
460 return flowMod.getXid();
468 List<OFFlowStatsEntry> entries =
new ArrayList<>();
469 IOFSwitch sw = ofSwitchService.getSwitch(dpid);
471 throw new IllegalArgumentException(String.format(
"Switch %s was not found", dpid));
474 OFFactory ofFactory = sw.getOFFactory();
475 OFFlowStatsRequest flowRequest = ofFactory.buildFlowStatsRequest()
476 .setOutGroup(OFGroup.ANY)
477 .setCookieMask(U64.ZERO)
481 Future<List<OFFlowStatsReply>> future = sw.writeStatsRequest(flowRequest);
482 List<OFFlowStatsReply> values = future.get(10, TimeUnit.SECONDS);
483 if (values != null) {
484 entries = values.stream()
485 .map(OFFlowStatsReply::getEntries)
486 .flatMap(List::stream)
487 .collect(Collectors.toList());
489 }
catch (ExecutionException | InterruptedException | TimeoutException e) {
490 logger.error(
"Could not get flow stats for {}.", dpid, e);
501 OFMeterConfigStatsReply values = null;
502 IOFSwitch sw = lookupSwitch(dpid);
504 throw new IllegalArgumentException(String.format(
"Switch %s was not found", dpid));
507 OFFactory ofFactory = sw.getOFFactory();
508 if (ofFactory.getVersion().compareTo(OF_13) < 0) {
510 String.format(
"Dumping of meters is not supported on the requested switch %s.", dpid));
513 OFMeterConfigStatsRequest meterRequest = ofFactory.buildMeterConfigStatsRequest()
514 .setMeterId(0xffffffff)
518 ListenableFuture<OFMeterConfigStatsReply> future = sw.writeRequest(meterRequest);
519 values = future.get(5, TimeUnit.SECONDS);
520 }
catch (ExecutionException | InterruptedException | TimeoutException e) {
521 logger.error(
"Could not get meter config stats for {}.", dpid, e);
531 public long installMeter(
final DatapathId dpid,
final long bandwidth,
final long burstSize,
final long meterId)
534 logger.info(
"skip installing meter {} on switch {} width bandwidth {}", meterId, dpid, bandwidth);
538 IOFSwitch sw = lookupSwitch(dpid);
540 if (
OVS_MANUFACTURER.equals(sw.getSwitchDescription().getManufacturerDescription())) {
541 logger.info(
"skip installing meter {} on OVS switch {} width bandwidth {}", meterId, dpid, bandwidth);
545 long meterCommandXid;
547 if (sw.getOFFactory().getVersion().compareTo(OF_12) <= 0) {
548 meterCommandXid = installLegacyMeter(sw, dpid, bandwidth, burstSize, meterId);
550 meterCommandXid = buildAndinstallMeter(sw, dpid, bandwidth, burstSize, meterId);
555 sendBarrierRequest(sw);
557 return meterCommandXid;
562 return ofSwitchService.getAllSwitchMap();
571 public long deleteMeter(
final DatapathId dpid,
final long meterId)
574 logger.info(
"skip deleting meter {} from switch {}", meterId, dpid);
578 IOFSwitch sw = lookupSwitch(dpid);
579 if (
OVS_MANUFACTURER.equals(sw.getSwitchDescription().getManufacturerDescription())) {
580 logger.info(
"skip deleting meter {} from OVS switch {}", meterId, dpid);
584 if (sw.getOFFactory().getVersion().compareTo(OF_12) <= 0) {
585 return deleteLegacyMeter(sw, dpid, meterId);
587 return buildAndDeleteMeter(sw, dpid, meterId);
595 List<OFFlowStatsEntry> flowStatsBefore =
dumpFlowTable(dpid);
596 IOFSwitch sw = lookupSwitch(dpid);
597 OFFactory ofFactory = sw.getOFFactory();
599 Set<Long> removedRules =
new HashSet<>();
601 for (OFFlowStatsEntry flowStatsEntry : flowStatsBefore) {
602 long flowCookie = flowStatsEntry.getCookie().getValue();
606 OFFlowDelete flowDelete = ofFactory.buildFlowDelete()
607 .setCookie(U64.of(flowCookie))
608 .setCookieMask(U64.NO_MASK)
610 pushFlow(sw,
"--DeleteFlow--", flowDelete);
612 logger.info(
"Rule with cookie {} is to be removed from switch {}.", flowCookie, dpid);
614 removedRules.add(flowCookie);
619 sendBarrierRequest(sw);
622 Set<Long> cookiesAfter = flowStatsAfter.stream()
623 .map(entry -> entry.getCookie().getValue())
624 .collect(Collectors.toSet());
626 flowStatsBefore.stream()
627 .map(entry -> entry.getCookie().getValue())
628 .filter(cookie -> !cookiesAfter.contains(cookie))
629 .filter(cookie -> !removedRules.contains(cookie))
631 logger.warn(
"Rule with cookie {} has been removed although not requested. Switch {}.", cookie,
633 removedRules.add(cookie);
636 cookiesAfter.stream()
637 .filter(removedRules::contains)
639 logger.warn(
"Rule with cookie {} was requested to be removed, but it still remains. Switch {}.",
641 removedRules.remove(cookie);
644 return new ArrayList<>(removedRules);
651 List<OFFlowStatsEntry> flowStatsBefore =
dumpFlowTable(dpid);
653 IOFSwitch sw = lookupSwitch(dpid);
654 OFFactory ofFactory = sw.getOFFactory();
657 OFFlowDelete dropFlowDelete = buildFlowDeleteByCriteria(ofFactory, criteriaEntry);
659 logger.info(
"Rules by criteria {} are to be removed from switch {}.", criteria, dpid);
661 pushFlow(sw,
"--DeleteFlow--", dropFlowDelete);
665 sendBarrierRequest(sw);
668 Set<Long> cookiesAfter = flowStatsAfter.stream()
669 .map(entry -> entry.getCookie().getValue())
670 .collect(Collectors.toSet());
672 return flowStatsBefore.stream()
673 .map(entry -> entry.getCookie().getValue())
674 .filter(cookie -> !cookiesAfter.contains(cookie))
675 .peek(cookie -> logger.info(
"Rule with cookie {} has been removed from switch {}.", cookie, dpid))
676 .collect(Collectors.toList());
691 IOFSwitch sw = lookupSwitch(dpid);
692 OFFactory ofFactory = sw.getOFFactory();
696 if (ofFactory.getVersion().compareTo(OF_12) > 0) {
697 logger.debug(
"installing unicast verification match for {}", dpid);
699 logger.debug(
"not installing unicast verification match for {}", dpid);
704 logger.debug(
"installing verification rule for {}", dpid);
706 Match match = matchVerification(sw, isBroadcast);
707 ArrayList<OFAction> actionList =
new ArrayList<>(2);
708 actionList.add(actionSendToController(sw));
709 actionList.add(actionSetDstMac(sw, dpidToMac(sw)));
710 OFInstructionApplyActions instructionApplyActions = ofFactory.instructions()
711 .applyActions(actionList).createBuilder().build();
713 OFFlowMod flowMod = buildFlowMod(ofFactory, match, null, instructionApplyActions,
715 String flowname = (isBroadcast) ?
"Broadcast" :
"Unicast";
716 flowname +=
"--VerificationFlow--" + dpid.toString();
717 pushFlow(sw, flowname, flowMod);
733 IOFSwitch sw = lookupSwitch(dpid);
734 OFFactory ofFactory = sw.getOFFactory();
736 Match match = simpleDstMatch(ofFactory, dstMac, dstMask);
737 OFFlowMod flowMod = buildFlowMod(ofFactory, match, null, null, cookie, priority);
738 String flowName =
"--CustomDropRule--" + dpid.toString();
739 pushFlow(sw, flowName, flowMod);
749 IOFSwitch sw = lookupSwitch(dpid);
750 OFFactory ofFactory = sw.getOFFactory();
752 if (ofFactory.getVersion() == OF_12) {
753 logger.debug(
"Skip installation of drop flow for switch {}", dpid);
755 logger.debug(
"Installing drop flow for switch {}", dpid);
756 OFFlowMod flowMod = buildFlowMod(ofFactory, null, null, null,
DROP_RULE_COOKIE, 1);
757 String flowName =
"--DropRule--" + dpid.toString();
758 pushFlow(sw, flowName, flowMod);
762 private long buildAndinstallMeter(
final IOFSwitch sw,
final DatapathId dpid,
final long bandwidth,
763 final long burstSize,
final long meterId)
765 logger.debug(
"installing meter {} on switch {} width bandwidth {}", meterId, dpid, bandwidth);
767 Set<OFMeterFlags> flags =
new HashSet<>(asList(OFMeterFlags.KBPS, OFMeterFlags.BURST));
768 OFFactory ofFactory = sw.getOFFactory();
770 OFMeterBandDrop.Builder bandBuilder = ofFactory.meterBands()
773 .setBurstSize(burstSize);
775 OFMeterMod.Builder meterModBuilder = ofFactory.buildMeterMod()
777 .setCommand(OFMeterModCommand.ADD)
780 if (sw.getOFFactory().getVersion().compareTo(OF_13) > 0) {
781 meterModBuilder.setBands(singletonList(bandBuilder.build()));
783 meterModBuilder.setMeters(singletonList(bandBuilder.build()));
786 OFMeterMod meterMod = meterModBuilder.build();
788 return pushFlow(sw,
"--InstallMeter--", meterMod);
791 private long installLegacyMeter(
792 final IOFSwitch sw,
final DatapathId dpid,
793 final long bandwidth,
final long burstSize,
final long meterId)
794 throws OFInstallException {
795 logger.debug(
"installing legacy meter {} on OVS switch {} width bandwidth {}", meterId, dpid, bandwidth);
797 Set<OFLegacyMeterFlags> flags =
new HashSet<>(asList(OFLegacyMeterFlags.KBPS, OFLegacyMeterFlags.BURST));
798 OFFactory ofFactory = sw.getOFFactory();
800 OFLegacyMeterBandDrop.Builder bandBuilder = ofFactory.legacyMeterBandDrop(bandwidth, burstSize).createBuilder();
802 OFLegacyMeterMod meterMod = ofFactory.buildLegacyMeterMod()
804 .setCommand(OFLegacyMeterModCommand.ADD)
805 .setMeters(singletonList(bandBuilder.build()))
809 return pushFlow(sw,
"--InstallMeter", meterMod);
812 private long buildAndDeleteMeter(IOFSwitch sw,
final DatapathId dpid,
final long meterId)
813 throws OFInstallException {
814 logger.debug(
"deleting meter {} from switch {}", meterId, dpid);
816 OFFactory ofFactory = sw.getOFFactory();
818 OFMeterMod.Builder meterDeleteBuilder = ofFactory.buildMeterMod()
820 .setCommand(OFMeterModCommand.DELETE);
822 if (sw.getOFFactory().getVersion().compareTo(OF_13) > 0) {
823 meterDeleteBuilder.setBands(emptyList());
825 meterDeleteBuilder.setMeters(emptyList());
828 OFMeterMod meterDelete = meterDeleteBuilder.build();
830 return pushFlow(sw,
"--DeleteMeter--", meterDelete);
833 private long deleteLegacyMeter(
final IOFSwitch sw,
final DatapathId dpid,
final long meterId)
834 throws OFInstallException {
835 logger.debug(
"deleting legacy meter {} from switch {}", meterId, dpid);
837 OFFactory ofFactory = sw.getOFFactory();
839 OFLegacyMeterMod meterDelete = ofFactory.buildLegacyMeterMod()
841 .setMeters(emptyList())
842 .setCommand(OFLegacyMeterModCommand.DELETE)
845 return pushFlow(sw,
"--DeleteMeter--", meterDelete);
848 private OFFlowDelete buildFlowDeleteByCriteria(OFFactory ofFactory, DeleteRulesCriteria criteria) {
849 OFFlowDelete.Builder builder = ofFactory.buildFlowDelete();
850 if (criteria.getCookie() != null) {
851 builder.setCookie(U64.of(criteria.getCookie()));
852 builder.setCookieMask(U64.NO_MASK);
855 if (criteria.getInPort() != null) {
857 Match match = matchFlow(ofFactory, criteria.getInPort(),
858 Optional.ofNullable(criteria.getInVlan()).orElse(0));
859 builder.setMatch(match);
861 }
else if (criteria.getInVlan() != null) {
863 Match.Builder matchBuilder = ofFactory.buildMatch();
864 matchVlan(ofFactory, matchBuilder, criteria.getInVlan());
865 builder.setMatch(matchBuilder.build());
868 if (criteria.getPriority() != null) {
870 builder.setPriority(criteria.getPriority());
873 if (criteria.getOutPort() != null) {
875 builder.setOutPort(OFPort.of(criteria.getOutPort()));
878 return builder.build();
881 private OFBarrierReply sendBarrierRequest(IOFSwitch sw) {
882 OFFactory ofFactory = sw.getOFFactory();
883 OFBarrierRequest barrierRequest = ofFactory.buildBarrierRequest().build();
885 OFBarrierReply
result = null;
887 ListenableFuture<OFBarrierReply> future = sw.writeRequest(barrierRequest);
888 result = future.get(10, TimeUnit.SECONDS);
889 }
catch (ExecutionException | InterruptedException | TimeoutException e) {
890 logger.error(
"Could not get a barrier reply for {}.", sw.getId(), e);
896 private List<Long> deleteRulesWithCookie(
final DatapathId dpid, Long... cookiesToRemove)
897 throws SwitchOperationException {
898 DeleteRulesCriteria[] criteria = Stream.of(cookiesToRemove)
899 .map(cookie -> DeleteRulesCriteria.builder().cookie(cookie).build())
900 .toArray(DeleteRulesCriteria[]::
new);
915 private Match matchFlow(
final OFFactory ofFactory,
final int inputPort,
final int vlanId) {
916 Match.Builder mb = ofFactory.buildMatch();
920 mb.setExact(MatchField.IN_PORT, OFPort.of(inputPort));
922 matchVlan(ofFactory, mb, vlanId);
928 private void matchVlan(
final OFFactory ofFactory,
final Match.Builder matchBuilder,
final int vlanId) {
929 if (0 <= OF_12.compareTo(ofFactory.getVersion())) {
930 matchBuilder.setMasked(MatchField.VLAN_VID, OFVlanVidMatch.ofVlan(vlanId),
931 OFVlanVidMatch.ofRawVid(OF10_VLAN_MASK));
933 matchBuilder.setExact(MatchField.VLAN_VID, OFVlanVidMatch.ofVlan(vlanId));
945 private List<OFAction> replaceSchemeOutputVlanTypeToOfActionList(OFFactory ofFactory,
int outputVlanId,
946 OutputVlanType outputVlanType) {
947 List<OFAction> actionList;
949 switch (outputVlanType) {
952 actionList = singletonList(actionReplaceVlan(ofFactory, outputVlanId));
956 actionList = singletonList(actionPopVlan(ofFactory));
959 actionList = emptyList();
960 logger.error(
"Unknown OutputVlanType: " + outputVlanType);
974 private List<OFAction> pushSchemeOutputVlanTypeToOfActionList(OFFactory ofFactory,
int outputVlanId,
975 OutputVlanType outputVlanType) {
976 List<OFAction> actionList =
new ArrayList<>(2);
978 switch (outputVlanType) {
980 actionList.add(actionPushVlan(ofFactory, ETH_TYPE));
981 actionList.add(actionReplaceVlan(ofFactory, outputVlanId));
984 actionList.add(actionReplaceVlan(ofFactory, outputVlanId));
988 actionList.add(actionPopVlan(ofFactory));
993 logger.error(
"Unknown OutputVlanType: " + outputVlanType);
1007 private List<OFAction> outputVlanTypeToOfActionList(OFFactory ofFactory,
int outputVlanId,
1008 OutputVlanType outputVlanType) {
1009 return replaceSchemeOutputVlanTypeToOfActionList(ofFactory, outputVlanId, outputVlanType);
1019 private List<OFAction> inputVlanTypeToOfActionList(OFFactory ofFactory,
int transitVlanId,
1020 OutputVlanType outputVlanType) {
1021 List<OFAction> actionList =
new ArrayList<>(3);
1022 if (OutputVlanType.PUSH.equals(outputVlanType) || OutputVlanType.NONE.equals(outputVlanType)) {
1023 actionList.add(actionPushVlan(ofFactory, ETH_TYPE));
1025 actionList.add(actionReplaceVlan(ofFactory, transitVlanId));
1036 private OFAction actionSetOutputPort(
final OFFactory ofFactory,
final int outputPort) {
1037 OFActions actions = ofFactory.actions();
1038 return actions.buildOutput().setMaxLen(0xFFFFFFFF).setPort(OFPort.of(outputPort)).
build();
1048 private OFAction actionReplaceVlan(
final OFFactory factory,
final int newVlan) {
1049 OFOxms oxms = factory.oxms();
1050 OFActions actions = factory.actions();
1052 if (OF_12.compareTo(factory.getVersion()) == 0) {
1053 return actions.buildSetField().setField(oxms.buildVlanVid()
1054 .setValue(OFVlanVidMatch.ofRawVid((
short) newVlan))
1057 return actions.buildSetField().setField(oxms.buildVlanVid()
1058 .setValue(OFVlanVidMatch.ofVlan(newVlan))
1070 private OFAction actionPushVlan(
final OFFactory ofFactory,
final int etherType) {
1071 OFActions actions = ofFactory.actions();
1072 return actions.buildPushVlan().setEthertype(EthType.of(etherType)).
build();
1081 private OFAction actionPopVlan(
final OFFactory ofFactory) {
1082 OFActions actions = ofFactory.actions();
1083 return actions.popVlan();
1097 private OFFlowMod buildFlowMod(
final OFFactory ofFactory,
final Match match,
final OFInstructionMeter meter,
1098 final OFInstructionApplyActions actions,
final long cookie,
final int priority) {
1099 OFFlowMod.Builder fmb = ofFactory.buildFlowAdd();
1100 fmb.setIdleTimeout(FlowModUtils.INFINITE_TIMEOUT);
1101 fmb.setHardTimeout(FlowModUtils.INFINITE_TIMEOUT);
1102 fmb.setBufferId(OFBufferId.NO_BUFFER);
1103 fmb.setCookie(U64.of(cookie));
1104 fmb.setPriority(priority);
1105 List<OFInstruction> instructions =
new ArrayList<>(2);
1108 if (meter != null) {
1109 instructions.add(meter);
1113 if (actions != null) {
1114 instructions.add(actions);
1118 if (match != null) {
1119 fmb.setMatch(match);
1122 return fmb.setInstructions(instructions).build();
1131 private MacAddress dpidToMac(
final IOFSwitch sw) {
1132 return MacAddress.of(Arrays.copyOfRange(sw.getId().getBytes(), 2, 8));
1142 private Match matchVerification(
final IOFSwitch sw,
final boolean isBroadcast) {
1143 MacAddress dstMac = isBroadcast ? MacAddress.of(VERIFICATION_BCAST_PACKET_DST) : dpidToMac(sw);
1144 Builder builder = sw.getOFFactory().buildMatch();
1145 builder.setMasked(MatchField.ETH_DST, dstMac, MacAddress.NO_MASK);
1146 return builder.build();
1157 private OFAction actionSendToController(
final IOFSwitch sw) {
1158 OFActions actions = sw.getOFFactory().actions();
1159 return actions.buildOutput().setMaxLen(0xFFffFFff).setPort(OFPort.CONTROLLER)
1170 private OFAction actionSetDstMac(
final IOFSwitch sw,
final MacAddress macAddress) {
1171 OFOxms oxms = sw.getOFFactory().oxms();
1172 OFActions actions = sw.getOFFactory().actions();
1173 return actions.buildSetField()
1174 .setField(oxms.buildEthDst().setValue(macAddress).build()).
build();
1188 private Match simpleDstMatch(OFFactory ofFactory, String dstMac, String dstMask) {
1190 if (dstMac != null && dstMask != null && dstMac.length() > 0 && dstMask.length() > 0) {
1191 Builder builder = ofFactory.buildMatch();
1192 builder.setMasked(MatchField.ETH_DST, MacAddress.of(dstMac), MacAddress.NO_MASK);
1193 match = builder.build();
1209 private long pushFlow(
final IOFSwitch sw,
final String flowId,
final OFMessage flowMod)
throws OFInstallException {
1210 logger.info(
"installing {} flow: {}", flowId, flowMod);
1212 if (! sw.write(flowMod)) {
1213 throw new OFInstallException(sw.getId(), flowMod);
1216 return flowMod.getXid();
1226 private IOFSwitch lookupSwitch(DatapathId dpId)
throws SwitchOperationException {
1227 IOFSwitch swInfo = ofSwitchService.getSwitch(dpId);
1228 if (swInfo == null) {
1229 throw new SwitchOperationException(dpId, String.format(
"Switch %s was not found", dpId));
1238 private static final class SafeData {
1240 static final int PRIORITY_IGNORE_THRESHOLD = 100;
1241 private static final int window = 5;
1243 private static final int PACKET_COUNT_MIN = 5;
1251 List<Long> timestamps;
1252 Map<Long, List<Long>> ruleByteCounts;
1253 Map<Long, List<Long>> rulePktCounts;
1256 int broadcastRuleStage;
1257 int unicastRuleStage;
1259 void consumeData(
long timestamp, List<OFFlowStatsEntry> flowEntries) {
1260 timestamps.add(timestamp);
1262 for (OFFlowStatsEntry flowStatsEntry : flowEntries) {
1263 if (flowStatsEntry.getPriority() <= PRIORITY_IGNORE_THRESHOLD) {
1267 long flowCookie = flowStatsEntry.getCookie().getValue();
1268 if (!ruleByteCounts.containsKey(flowCookie)) {
1269 ruleByteCounts.put(flowCookie,
new ArrayList<>());
1270 rulePktCounts.put(flowCookie,
new ArrayList<>());
1272 ruleByteCounts.get(flowCookie).add(flowStatsEntry.getByteCount().getValue());
1273 rulePktCounts.get(flowCookie).add(flowStatsEntry.getPacketCount().getValue());
1278 boolean shouldApplyRule(
int stage) {
1279 return timestamps.size() == ((stage - 1) * 2 + 1) * window;
1282 boolean shouldTestRule(
int stage) {
1283 return timestamps.size() == ((stage - 1) * 2 + 2) * window;
1287 List<Integer> getRuleEffect(
int stage) {
1288 int start = (stage - 1) * 2;
1289 int middle = start + 1;
1290 int end = middle + 1;
1294 for (List<Long> packets : rulePktCounts.values()) {
1295 long packetsBefore = packets.get(middle) - packets.get(start);
1298 long packetsAfter = packets.get(end) - packets.get(middle + 1);
1299 boolean ruleHadNoEffect = (packetsBefore > PACKET_COUNT_MIN && packetsAfter > 0);
1300 if (ruleHadNoEffect) {
1306 return asList(badCounts, goodCounts);
1309 boolean isRuleOkay(List<Integer> ruleEffect) {
1314 int badCounts = ruleEffect.get(0);
1315 return badCounts == 0;
1319 private Map<DatapathId, SafeData> safeSwitches =
new HashMap<>();
1320 private long lastRun = 0L;
1329 if (!safeSwitches.containsKey(dpid)) {
1330 SafeData safeData = safeSwitches.put(dpid,
new SafeData());
1331 safeData.dpid = dpid;
1340 safeSwitches.remove(dpid);
1343 private static final long tick_length = 1000;
1344 private static final boolean BROADCAST =
true;
1345 private static final int DROP_STAGE = 1;
1346 private static final int BROADCAST_STAGE = 2;
1347 private static final int UNICAST_STAGE = 3;
1351 private static final int RULE_APPLIED = 1;
1352 private static final int RULE_TESTED = 2;
1353 private static final int RULE_IS_GOOD = 2;
1354 private static final int RULE_NO_GOOD = 3;
1359 long time = System.currentTimeMillis();
1360 if (time - lastRun < tick_length) {
1366 Collection<SafeData> values = safeSwitches.values();
1367 for (SafeData safeData : values) {
1371 int datapoints = safeData.timestamps.size();
1373 if (safeData.dropRuleStage < RULE_TESTED) {
1375 logger.debug(
"SAFE MODE: Collected Data during Drop Rule Stage for '{}' ", safeData.dpid);
1376 if (safeData.shouldApplyRule(DROP_STAGE)) {
1377 logger.info(
"SAFE MODE: APPLY Drop Rule for '{}' ", safeData.dpid);
1378 safeData.dropRuleStage = RULE_APPLIED;
1380 }
else if (safeData.shouldTestRule(DROP_STAGE)) {
1381 List<Integer> ruleEffect = safeData.getRuleEffect(DROP_STAGE);
1382 if (safeData.isRuleOkay(ruleEffect)) {
1383 logger.info(
"SAFE MODE: Drop Rule is GOOD for '{}' ", safeData.dpid);
1384 safeData.dropRuleStage = RULE_IS_GOOD;
1386 logger.warn(
"SAFE MODE: Drop Rule is BAD for '{}'. " 1387 +
"Good Packet Count: {}. Bad Packet Count: {} ",
1388 safeData.dpid, ruleEffect.get(0), ruleEffect.get(1));
1389 safeData.dropRuleStage = RULE_NO_GOOD;
1394 }
else if (safeData.broadcastRuleStage < RULE_TESTED) {
1396 logger.debug(
"SAFE MODE: Collected Data during Broadcast Verification Rule " 1397 +
"Stage for '{}' ", safeData.dpid);
1398 if (safeData.shouldApplyRule(BROADCAST_STAGE)) {
1399 logger.info(
"SAFE MODE: APPLY Broadcast Verification Rule for '{}' ", safeData.dpid);
1400 safeData.broadcastRuleStage = RULE_APPLIED;
1402 }
else if (safeData.shouldTestRule(BROADCAST_STAGE)) {
1403 List<Integer> ruleEffect = safeData.getRuleEffect(BROADCAST_STAGE);
1404 if (safeData.isRuleOkay(ruleEffect)) {
1405 logger.info(
"SAFE MODE: Broadcast Verification Rule is GOOD for '{}' ", safeData.dpid);
1406 safeData.broadcastRuleStage = RULE_IS_GOOD;
1408 logger.warn(
"SAFE MODE: Broadcast Verification Rule is BAD for '{}'. " 1409 +
"Good Packet Count: {}. Bad Packet Count: {} ",
1410 safeData.dpid, ruleEffect.get(0), ruleEffect.get(1));
1411 safeData.broadcastRuleStage = RULE_NO_GOOD;
1415 }
else if (safeData.unicastRuleStage < RULE_TESTED) {
1418 logger.debug(
"SAFE MODE: Collected Data during Unicast Verification Rule Stage " 1419 +
"for '{}' ", safeData.dpid);
1420 if (safeData.shouldApplyRule(UNICAST_STAGE)) {
1421 logger.info(
"SAFE MODE: APPLY Unicast Verification Rule for '{}' ", safeData.dpid);
1422 safeData.unicastRuleStage = RULE_APPLIED;
1424 }
else if (safeData.shouldTestRule(UNICAST_STAGE)) {
1425 List<Integer> ruleEffect = safeData.getRuleEffect(UNICAST_STAGE);
1426 if (safeData.isRuleOkay(ruleEffect)) {
1427 logger.info(
"SAFE MODE: Unicast Verification Rule is GOOD for '{}' ", safeData.dpid);
1428 safeData.unicastRuleStage = RULE_IS_GOOD;
1430 logger.warn(
"SAFE MODE: Unicast Verification Rule is BAD for '{}'. " 1431 +
"Good Packet Count: {}. Bad Packet Count: {} ",
1432 safeData.dpid, ruleEffect.get(0), ruleEffect.get(1));
1433 safeData.unicastRuleStage = RULE_NO_GOOD;
1441 logger.info(
"SAFE MODE: COMPLETED base rules for '{}' ", safeData.dpid);
1442 IOFSwitch sw = lookupSwitch(safeData.dpid);
1446 values.remove(safeData);
1449 logger.error(
"Error while switch {} was in safe mode. Removing switch from safe " 1450 +
"mode and NOT SENDING ACTIVATION. \nERROR: {}", safeData.dpid, e);
1451 values.remove(safeData);
1463 kafkaProducer.
postMessage(topoDiscoTopic, message);
1471 if (sw.getEnabledPortNumbers() != null) {
1472 for (OFPort
p : sw.getEnabledPortNumbers()) {
1476 PortChangeType.UP));
1485 IOFSwitch sw = lookupSwitch(dpId);
1487 boolean makeChanges =
false;
1488 if (portAdminDown != null) {
1490 updatePortStatus(sw, portNumber, portAdminDown);
1494 sendBarrierRequest(sw);
1499 Set<OFPortConfig>
config =
new HashSet<>(1);
1501 config.add(OFPortConfig.PORT_DOWN);
1504 Set<OFPortConfig> portMask = ImmutableSet.of(OFPortConfig.PORT_DOWN);
1506 final OFFactory ofFactory = sw.getOFFactory();
1507 OFPortMod ofPortMod = ofFactory.buildPortMod()
1508 .setPortNo(OFPort.of(portNumber))
1510 .setHwAddr(getPortHwAddress(sw, portNumber))
1515 if (!sw.write(ofPortMod)) {
1516 throw new SwitchOperationException(sw.getId(),
1517 String.format(
"Unable to update port configuration: %s", ofPortMod));
1520 logger.debug(
"Successfully updated port status {}", ofPortMod);
1523 private MacAddress getPortHwAddress(IOFSwitch sw,
int portNumber) {
1524 OFPortDesc portDesc = sw.getPort(OFPort.of(portNumber));
1525 return portDesc.getHwAddr();
Map< Class<? extends IFloodlightService >, IFloodlightService > getServiceImpls()
long installMeter(final DatapathId dpid, final long bandwidth, final long burstSize, final long meterId)
String getTopoDiscoTopic()
void installDropFlow(final DatapathId dpid)
boolean isCallbackOrderingPrereq(OFType type, String name)
Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx)
long installEgressFlow(final DatapathId dpid, String flowId, final Long cookie, final int inputPort, final int outputPort, final int transitVlanId, final int outputVlanId, final OutputVlanType outputVlanType)
void init(FloodlightModuleContext context)
long installIngressFlow(final DatapathId dpid, final String flowId, final Long cookie, final int inputPort, final int outputPort, final int inputVlanId, final int transitVlanId, final OutputVlanType outputVlanType, final long meterId)
static Message buildSwitchMessage(final IOFSwitch sw, final SwitchState eventType)
Map< DatapathId, IOFSwitch > getAllSwitchMap()
static final int ETH_TYPE
static final int DEFAULT_RULE_PRIORITY
static Message buildPortMessage(final DatapathId switchId, final OFPort port, final PortChangeType type)
long VERIFICATION_BROADCAST_RULE_COOKIE
ConnectModeRequest.Mode connectMode(final ConnectModeRequest.Mode mode)
List< Long > deleteRulesByCriteria(final DatapathId dpid, DeleteRulesCriteria... criteria)
static boolean isPhysicalPort(OFPort p)
void sendPortUpEvents(final IOFSwitch sw)
Collection< Class<? extends IFloodlightService > > getModuleServices()
List< Long > deleteDefaultRules(final DatapathId dpid)
List< Long > deleteAllNonDefaultRules(final DatapathId dpid)
boolean isCallbackOrderingPostreq(OFType type, String name)
static final int VERIFICATION_RULE_PRIORITY
List< OFFlowStatsEntry > dumpFlowTable(final DatapathId dpid)
long installTransitFlow(final DatapathId dpid, final String flowId, final Long cookie, final int inputPort, final int outputPort, final int transitVlanId)
static ConfigurationProvider of(FloodlightModuleContext moduleContext, IFloodlightModule module)
void sendSwitchActivate(final IOFSwitch sw)
void installVerificationRule(final DatapathId dpid, final boolean isBroadcast)
void startSafeMode(final DatapathId dpid)
Collection< Class<? extends IFloodlightService > > getModuleDependencies()
long VERIFICATION_UNICAST_RULE_COOKIE
OFMeterConfigStatsReply dumpMeters(final DatapathId dpid)
void startUp(FloodlightModuleContext context)
void installDefaultRules(final DatapathId dpid)
void postMessage(final String topic, final Message message)
void configurePort(DatapathId dpId, int portNumber, Boolean portAdminDown)
long installOneSwitchFlow(final DatapathId dpid, final String flowId, final Long cookie, final int inputPort, final int outputPort, final int inputVlanId, final int outputVlanId, final OutputVlanType outputVlanType, final long meterId)
long deleteMeter(final DatapathId dpid, final long meterId)
void stopSafeMode(final DatapathId dpid)
static final String VERIFICATION_BCAST_PACKET_DST
static final long FLOW_COOKIE_MASK
void installDropFlowCustom(final DatapathId dpid, String dstMac, String dstMask, final long cookie, final int priority)