package org.opennaas.extensions.openflowswitch.driver.ryu.offorwarding.actionssets.actions; /* * #%L * OpenNaaS :: OpenFlow Switch :: Ryu driver v3.14 * %% * Copyright (C) 2007 - 2014 Fundació Privada i2CAT, Internet i Innovació a Catalunya * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import java.util.List; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.opennaas.core.resources.action.ActionException; import org.opennaas.core.resources.action.ActionResponse; import org.opennaas.core.resources.action.ActionResponse.STATUS; import org.opennaas.core.resources.protocol.IProtocolSessionManager; import org.opennaas.core.resources.protocol.ProtocolException; import org.opennaas.extensions.openflowswitch.capability.offorwarding.OpenflowForwardingActionSet; import org.opennaas.extensions.openflowswitch.driver.ryu.offorwarding.actionssets.RyuAction; import org.opennaas.extensions.openflowswitch.driver.ryu.offorwarding.actionssets.RyuConstants; import org.opennaas.extensions.openflowswitch.driver.ryu.protocol.client.IRyuStatsClient; import org.opennaas.extensions.openflowswitch.driver.ryu.protocol.client.model.RyuOFFlow; import org.opennaas.extensions.openflowswitch.helpers.ForwardingRuleUtils; import org.opennaas.extensions.openflowswitch.model.FloodlightOFAction; import org.opennaas.extensions.openflowswitch.model.FloodlightOFMatch; import org.opennaas.extensions.openflowswitch.model.OFFlow; import org.opennaas.extensions.openflowswitch.model.OFFlowTable; import org.opennaas.extensions.openflowswitch.model.OpenflowSwitchModel; /** * * @author Adrián Roselló Rey (i2CAT) * */ public class CreateOFForwardingAction extends RyuAction { private Log log = LogFactory.getLog(CreateOFForwardingAction.class); public static final String FORWARDING_ACTION = "output"; public CreateOFForwardingAction() { this.actionID = OpenflowForwardingActionSet.CREATEOFFORWARDINGRULE; } @Override public boolean checkParams(Object params) throws ActionException { if (params == null || !(params instanceof OFFlow)) throw new ActionException("Invalid parameters for action " + this.actionID); OFFlow flowRule = (OFFlow) params; if (flowRule.getName() == null || flowRule.getName().isEmpty()) throw new ActionException("No flow id given to params in action " + this.actionID); for (FloodlightOFAction action : flowRule.getActions()) { if (action.getType() == null || action.getType().isEmpty()) throw new ActionException("No OFAction type given to params in action " + this.actionID); if (action.getValue() == null || action.getValue().isEmpty()) throw new ActionException("No OFAction value given to params in action " + this.actionID); if (!(action.getType().equals(FORWARDING_ACTION))) throw new ActionException( "Wrong action type given to params in " + this.actionID + ". Expected was \"" + FORWARDING_ACTION + "\", but \"" + action .getType() + "\" was given."); } // if flowRule has priority if (flowRule.getPriority() != null && !flowRule.getPriority().isEmpty()) { // check priority is a number int priority; try { priority = Integer.parseInt(flowRule.getPriority()); } catch (NumberFormatException e) { throw new ActionException("Invalid priority in action " + this.actionID, e); } // check priority is in valid range int max = Integer.parseInt(RyuConstants.PRIORITY_MAX); int min = Integer.parseInt(RyuConstants.PRIORITY_MIN); if (priority > max || priority < min) { throw new ActionException("Invalid priority in action " + this.actionID + ". Valid range is [" + min + "," + max + "]"); } } return true; } @Override public ActionResponse execute(IProtocolSessionManager protocolSessionManager) throws ActionException { updateFlowWithControllerRequiredValues((OFFlow) params); // FIXME we assume forwarding rules are set in table 0 OFFlowTable flowTable = ((OpenflowSwitchModel) getModel()).getOfTables().get(0); List<OFFlow> forwardingRules = flowTable.getOfForwardingRules(); for (OFFlow ofFlow : forwardingRules) { compareForwardingRuleIsUnique(ofFlow, (OFFlow) params); if (ofFlow.getName().equals(((OFFlow) params).getName())) { log.debug("Removing existing flow with same id : " + ofFlow.getName()); RemoveOFForwardingAction action = new RemoveOFForwardingAction(); action.setParams(ofFlow); action.execute(protocolSessionManager); } } try { RyuOFFlow flowToPush; if (params instanceof RyuOFFlow) { flowToPush = new RyuOFFlow((RyuOFFlow) params); flowToPush.setDpid(getSwitchIdFromSession(protocolSessionManager)); } else flowToPush = new RyuOFFlow((OFFlow) params, getSwitchIdFromSession(protocolSessionManager)); // TODO we have to find another place where we could put switchId in model. setSwitchIdInModel(protocolSessionManager); IRyuStatsClient client = getRyuProtocolSession(protocolSessionManager).getRyuClientForUse(); log.debug("Sending forwarding rule to Ryu controller."); client.addFlowEntry(flowToPush); ((OpenflowSwitchModel) getModel()).getOfTables().get(0).getOfForwardingRules().add(flowToPush); } catch (Exception e) { log.error("Error pushing forwarding rule to Ryu. ", e); throw new ActionException(e); } ActionResponse response = new ActionResponse(); response.setStatus(STATUS.OK); return response; } private void updateFlowWithControllerRequiredValues(OFFlow flowToPush) { FloodlightOFMatch match = flowToPush.getMatch(); if (match != null) if (!StringUtils.isEmpty(match.getSrcIp()) || !StringUtils.isEmpty(match.getDstIp()) || !StringUtils.isEmpty(match.getTosBits())) match.setEtherType("2048"); } private void setSwitchIdInModel(IProtocolSessionManager protocolSessionManager) throws ProtocolException { OpenflowSwitchModel model = (OpenflowSwitchModel) getModel(); model.setSwitchId(getSwitchIdFromSession(protocolSessionManager)); } private void compareForwardingRuleIsUnique(OFFlow firstFlow, OFFlow secondFlow) throws ActionException { if (ForwardingRuleUtils.rulesWithSameMatch(firstFlow, secondFlow)) throw new ActionException("A forwarding rule with same information already exists in flow model."); } }