You are on page 1of 7

/*

* Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
/*
*
*/
package org.opendaylight.controller.tutorial_L2_forwarding.internal;
import
import
import
import
import
import
import
import
import
import
import
import
import
import

java.net.InetAddress;
java.net.UnknownHostException;
java.util.List;
java.util.ArrayList;
java.util.Arrays;
java.util.Collections;
java.util.HashSet;
java.util.Set;
java.lang.String;
java.util.Map;
java.util.HashMap;
java.util.Timer;
java.util.TimerTask;
java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import

org.opendaylight.controller.sal.core.ConstructionException;
org.opendaylight.controller.sal.core.Node;
org.opendaylight.controller.sal.core.NodeConnector;
org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService;
org.opendaylight.controller.sal.flowprogrammer.Flow;
org.opendaylight.controller.sal.packet.ARP;
org.opendaylight.controller.sal.packet.BitBufferHelper;
org.opendaylight.controller.sal.packet.Ethernet;
org.opendaylight.controller.sal.packet.IDataPacketService;
org.opendaylight.controller.sal.packet.IListenDataPacket;
org.opendaylight.controller.sal.packet.IPv4;
org.opendaylight.controller.sal.packet.TCP;
org.opendaylight.controller.sal.packet.Packet;
org.opendaylight.controller.sal.packet.PacketResult;
org.opendaylight.controller.sal.packet.RawPacket;
org.opendaylight.controller.sal.action.Action;
org.opendaylight.controller.sal.action.Output;
org.opendaylight.controller.sal.action.SetDlDst;
org.opendaylight.controller.sal.action.SetDlSrc;
org.opendaylight.controller.sal.action.SetNwDst;
org.opendaylight.controller.sal.action.SetNwSrc;
org.opendaylight.controller.sal.action.Flood;
org.opendaylight.controller.sal.match.Match;
org.opendaylight.controller.sal.match.MatchType;
org.opendaylight.controller.sal.match.MatchField;
org.opendaylight.controller.sal.utils.EtherTypes;
org.opendaylight.controller.sal.utils.IPProtocols;
org.opendaylight.controller.sal.utils.Status;

import org.opendaylight.controller.sal.utils.NetUtils;
import org.opendaylight.controller.switchmanager.ISwitchManager;
import org.opendaylight.controller.switchmanager.Subnet;
/* Class used for tutorial purposes. The bundle will perform
L2 learning switch, as well as the stateless load-balancer.
Hardcoded values for the stateless LB is set in init().
All other intelligence is in the receiveDataPacket() method.
*/
public class TutorialL2Forwarding implements IListenDataPacket {
private static final Logger logger = LoggerFactory
.getLogger(TutorialL2Forwarding.class);
private ISwitchManager switchManager = null;
private IFlowProgrammerService programmer = null;
private IDataPacketService dataPacketService = null;
private Map<Long, NodeConnector> mac_to_port = new HashMap<Long, NodeConnect
or>();
private String function = "switch";
public class ServerInfo {
public InetAddress ip;
public Long mac;
public ServerInfo(InetAddress ip, Long mac) {
this.ip = ip;
this.mac = mac;
}
}
//TODO: Stop keeping it hardcoded and allow used to enter through REST
InetAddress virtual_ip;
Long virtual_mac;
List<ServerInfo> server = new ArrayList<ServerInfo>();
int total_servers = 0;
int server_index = 0;
void setDataPacketService(IDataPacketService s) {
this.dataPacketService = s;
}
void unsetDataPacketService(IDataPacketService s) {
if (this.dataPacketService == s) {
this.dataPacketService = null;
}
}
public void setFlowProgrammerService(IFlowProgrammerService s)
{
this.programmer = s;
}
public void unsetFlowProgrammerService(IFlowProgrammerService s) {
if (this.programmer == s) {
this.programmer = null;
}
}
void setSwitchManager(ISwitchManager s) {

logger.debug("SwitchManager set");
this.switchManager = s;
}
void unsetSwitchManager(ISwitchManager s) {
if (this.switchManager == s) {
logger.debug("SwitchManager removed!");
this.switchManager = null;
}
}
/**
* Function called by the dependency manager when all the required
* dependencies are satisfied
*
*/
void init() {
try {
this.virtual_ip = InetAddress.getByName("10.0.0.5");
this.virtual_mac = 5L;
this.server.add(new ServerInfo(InetAddress.getByName("10.0.0.2"), 2L
));
this.server.add(new ServerInfo(InetAddress.getByName("10.0.0.3"), 3L
));
this.server.add(new ServerInfo(InetAddress.getByName("10.0.0.4"), 4L
));
this.total_servers = this.server.size();
}
catch (UnknownHostException e) {
logger.error("Grave problem. Hardcoding of server IPs failed");
}
logger.info("Initialized");
}
/**
* Function called by the dependency manager when at least one
* dependency become unsatisfied or when the component is shutting
* down because for example bundle is being stopped.
*
*/
void destroy() {
}
/**
* Function called by dependency manager after "init ()" is called
* and after the services provided by the class are registered in
* the service registry
*
*/
void start() {
logger.info("Started");
}
/**
* Function called by the dependency manager before the services
* exported by the component are unregistered, this will be
* followed by a "destroy ()" calls
*
*/

void stop() {
logger.info("Stopped");
}
private void floodPacket(RawPacket inPkt) {
NodeConnector incoming_connector = inPkt.getIncomingNodeConnector();
Node incoming_node = incoming_connector.getNode();
Set<NodeConnector> nodeConnectors =
this.switchManager.getUpNodeConnectors(incoming_node);
for (NodeConnector p : nodeConnectors) {
if (!p.equals(incoming_connector)) {
try {
RawPacket destPkt = new RawPacket(inPkt);
destPkt.setOutgoingNodeConnector(p);
this.dataPacketService.transmitDataPacket(destPkt);
} catch (ConstructionException e2) {
continue;
}
}
}
}
@Override
public PacketResult receiveDataPacket(RawPacket inPkt) {
if (inPkt == null) {
return PacketResult.IGNORED;
}
logger.trace("Received a frame of size: {}",
inPkt.getPacketData().length);
Packet formattedPak = this.dataPacketService.decodeDataPacket(inPkt);
NodeConnector incoming_connector = inPkt.getIncomingNodeConnector();
Node incoming_node = incoming_connector.getNode();
if (formattedPak instanceof Ethernet) {
byte[] srcMAC = ((Ethernet)formattedPak).getSourceMACAddress();
byte[] dstMAC = ((Ethernet)formattedPak).getDestinationMACAddress();
Object nextPak = formattedPak.getPayload();
try {
if (nextPak instanceof IPv4) {
InetAddress srcIP = InetAddress.getByAddress(NetUtils.intToB
yteArray4(((IPv4)nextPak).getSourceAddress()));
InetAddress dstIP = InetAddress.getByAddress(NetUtils.intToB
yteArray4(((IPv4)nextPak).getDestinationAddress()));
if (dstIP.equals(virtual_ip)) {
nextPak = ((IPv4)nextPak).getPayload();
if (nextPak instanceof TCP) {
short srcPort = ((TCP)nextPak).getSourcePort();
short dstPort = ((TCP)nextPak).getDestinationPort();
// Select server
int index = this.server_index % this.total_servers;
InetAddress selected_server_ip = this.server.get(in
dex).ip;
Long selected_server_mac = this.server.get(index).ma
c;

NodeConnector selected_server_connector = this.mac_t


o_port.get(selected_server_mac);
this.server_index += 1;
// Send out the first packet to the selected server
try {
RawPacket destPkt = new RawPacket(inPkt);
destPkt.setOutgoingNodeConnector(selected_server
_connector);
this.dataPacketService.transmitDataPacket(destPk
t);
} catch (ConstructionException e2) {
logger.warn("Could not create packet for PACKET_
OUT");
return PacketResult.CONSUME;
}
// Setup match rules for forward direction
// based on the stateless LB logic
Match match = new Match();
match.setField(MatchType.DL_TYPE, EtherTypes.IPv4.sh
ortValue());
match.setField(MatchType.NW_PROTO, IPProtocols.TCP.b
yteValue());
match.setField(MatchType.DL_SRC, srcMAC);
match.setField(MatchType.NW_SRC, srcIP);
match.setField(MatchType.TP_SRC, srcPort);
match.setField(MatchType.DL_DST, dstMAC);
match.setField(MatchType.NW_DST, dstIP);
match.setField(MatchType.TP_DST, dstPort);
match.setField(MatchType.IN_PORT, incoming_connector
);
// 3 actions needed for the forward direction
List<Action> actions = new ArrayList<Action>();
actions.add(new SetDlDst(Arrays.copyOfRange(
BitBufferHelper.toByteArray(selected_server_
mac),2,8)));
actions.add(new SetNwDst(selected_server_ip));
actions.add(new Output(selected_server_connector));
Flow f = new Flow(match, actions);
f.setIdleTimeout((short)10);
// Modify the flow on the network node
Status status = programmer.addFlow(incoming_node, f)
;
if (!status.isSuccess()) {
logger.warn("Forward direction: {}", status.getD
escription());
return PacketResult.CONSUME;
}
logger.info("Installed forward flow {} in node {}",
f, incoming_node);
//Setup rules in reverse direction
Match reverse_match = match.reverse();
reverse_match.setField(MatchType.DL_SRC, Arrays.copy
OfRange(
BitBufferHelper.toByteArray(selected_server_

mac),2,8));
reverse_match.setField(MatchType.NW_SRC, selected_se
rver_ip);
reverse_match.setField(MatchType.IN_PORT, selected_s
erver_connector);
// 3 actions needed for the reverse direction
List<Action> reverse_actions = new ArrayList<Action>
();
reverse_actions.add(new SetDlSrc(dstMAC));
reverse_actions.add(new SetNwSrc(dstIP));
reverse_actions.add(new Output(incoming_connector));
Flow reverse_f = new Flow(reverse_match, reverse_act
ions);
reverse_f.setIdleTimeout((short)10);
// Modify the flow on the network node
status = programmer.addFlow(incoming_node, reverse_f
);
if (!status.isSuccess()) {
logger.warn("Reverse direction: {}", status.getD
escription());
}
logger.info("Installed reverse flow {} in node {}",
reverse_f, incoming_node);
return PacketResult.CONSUME;
}
}
}
}
catch (UnknownHostException e1) {
return PacketResult.IGNORED;
}
// Switch implementation
long srcMAC_val = BitBufferHelper.toNumber(srcMAC);
long dstMAC_val = BitBufferHelper.toNumber(dstMAC);
this.mac_to_port.put(srcMAC_val, incoming_connector);
Match match = new Match();
match.setField(MatchType.IN_PORT, incoming_connector);
match.setField(MatchType.DL_DST, dstMAC.clone());
NodeConnector dst_connector;
// Do I know the destination MAC?
if ((dst_connector = this.mac_to_port.get(dstMAC_val)) != null) {
List<Action> actions = new ArrayList<Action>();
actions.add(new Output(dst_connector));
Flow f = new Flow(match, actions);
f.setIdleTimeout((short)10);
// Modify the flow on the network node
Status status = programmer.addFlow(incoming_node, f);
if (!status.isSuccess()) {
logger.warn(

"SDN Plugin failed to program the flow: {}. The fail


ure is: {}",
f, status.getDescription());
return PacketResult.IGNORED;
}
logger.info("Installed flow {} in node {}",
f, incoming_node);
}
else
floodPacket(inPkt);
}
return PacketResult.IGNORED;
}
}

You might also like