SDN开发实战(1)-透明HTTP代理[Openflow+floodlight]

SDN开发实战(1)-透明HTTP代理[Openflow+floodlight]
1. SDN
软件定义⽹络(Software Defined Network, SDN),是Emulex⽹络⼀种新型⽹络创新架构,是⽹络虚拟化的⼀种实现⽅式,其核⼼技术OpenFlow通过将⽹络设备控制⾯与数据⾯分离开来,从⽽实现了⽹络流量的灵活控制,使⽹络作为管道变得更加智能
Openflow+floodlight
Openflow是SDN实现的重要的⼀个技术⼿段,由斯坦福⾼性能⽹络实验室开发,如今已形成了Openflow论坛。在Openflow框架中(如下图),每个主机(host)连接着Openflow交换机(Openflow Switch),交换机中的流量表(flow table)由Openflow的控制器控制,通过监视并改变每个Switch中的流量表,各个主机之间的通讯能够很灵活的被Controller控制,⽽Controller可通过编程实现,这样就从软件层⾯上直接控制了⽹络设备中的数据转发,从⽽定义整个⽹络
Openflow框架中的控制器有很多开源库可以实现:
Java: Beacon, Floodlight
Python: POX, Ryu, NOX (Deprecated)
Ruby: Trema
热休克蛋白此博客使⽤基于Java的Floodlight库开发控制器,⽤Mininet来模拟虚拟的主机和Openflow Switch,Mi
ninet是轻量级的软件定义⽹络系统平台,同时提供了对 OpenFlow 协议的⽀持,下⾯给出⼏个有⽤的传送门:
2. 透明HTTP代理
代理服务器的功能就是代理⽤户访问⽹络信息,代理分正向代理、反向代理、透明代理等,透明代理就是指⽤户并不知道代理服务器的存在,代理服务器会修改⽤户发送的request fields(报⽂),并会传送真实IP。关于代理服务器请看
这⾥,我们为了学习SDN开发,做出的透明HTTP代理应⽤,并不是真正意义上的透明代理,因为我们并不是注重在代理服务器本⾝,⽽是研究如何通过openflow+floodlight实现控制整个⽹络的转发,模拟的⽹络功能可以实现透明HTTP代理功能
我们将创建如上图⼀样的拓扑⽹络,具有三个虚拟交换机s1、s2、s3(使⽤的是Open vSwitch,⽽⾮标准的Openflow Switch),四个虚拟主机h1、h2、h3、prox,以及⼀个控制器c0:
其中,prox为具有代理服务器的虚拟主机,10.0.0.x代表每个主机的IP地址
hx-eth0代表主机hx的⽹卡适配器,sx-ethx则代表交换机sx的第x个⽹卡sx-ethx
控制器c0由Floodlight实现,虚拟交换机和主机由Mininet模拟,之间使⽤TCP通讯,端⼝6653
根据上⾯的描述,我们可以看出只有h1和h2连接着同⼀个交换机,prox和h3分别连接各⾃的交换机s2和s3,因此我们现在定义各个主机的⾓⾊和整个⽹络的转发策略(Policy)
1. h1和h2代表两个⽤户的主机,能通过同⼀个交换机直接互联
2. h3代表⽹站服务器,⾥⾯有h1和h2想要访问的⽹络资源
3. h1和h2并不能直接访问h3,需要通过prox代理服务器转发package
4. h1和h2并不知道代理服务器prox的存在,⽽且⽆法ping通prox
5. 所有的连接为双向有效(bi-bridge)
3. 代码实现[]
3.1 Floodlight
我们使⽤的是最新版的v1.3版本的Floodlight (master), 请先参考Floodlight官⽅教程-,编写⼀个⾃定义的控制器其实也就是增加⼀个模块,⼀个继承了IOFMessageListener和IFloodlightModule接⼝的java类,因此需要覆写接⼝中所有的⽅法。
1.我们新建⼀个TransHttpProxyDemo类如下:
package ansHttpProxy;
import java.util.Collection;
import java.util.Map;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFType;
import org.pes.MacAddress;
import FloodlightContext;
import IOFMessageListener;
import IOFSwitch;
import odule.FloodlightModuleContext;
import odule.FloodlightModuleException;
import odule.IFloodlightModule;
import odule.IFloodlightService;
public class TransHttpProxyDemo implements IOFMessageListener, IFloodlightModule {
@Override
public String getName() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isCallbackOrderingPrereq(OFType type, String name) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isCallbackOrderingPostreq(OFType type, String name) {
// TODO Auto-generated method stub
return false;
}
@Override
public Collection<Class<? extends IFloodlightService>> getModuleServices() {
// TODO Auto-generated method stub
return null;
}
@Override
public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() { // TODO Auto-generated method stub
return null;
}
@Override
public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
// TODO Auto-generated method stub
return null;
}
@Override
public void init(FloodlightModuleContext context)
throws FloodlightModuleException {
// TODO Auto-generated method stub
}
@Override
public void startUp(FloodlightModuleContext context) {
/
/ TODO Auto-generated method stub
}
@Override
public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
// TODO Auto-generated method stub
return null;
}
}
2.然后我们事先定义四个主机的Mac地址以及⼀个调试主机Magic的Mac地址(后⾯会讲),然后是主机连接的模式的枚举(直接连接、通过代理、⽆法连接),然后是⼀些我们即将⽤到的变量,相关类的包请⾃⾏⽤eclipse导⼊:
protected static final MacAddress MAGIC = MacAddress.of("00:11:00:11:00:11");
protected static final MacAddress H1 = MacAddress.of("00:00:00:00:00:01");
protected static final MacAddress H2 = MacAddress.of("00:00:00:00:00:02");
protected static final MacAddress H3 = MacAddress.of("00:00:00:00:00:03");
protected static final MacAddress PX = MacAddress.of("00:00:00:00:00:04");
protected enum RouteMode {
ROUTE_DIRECT, ROUTE_PROXY, ROUTE_DROP,
};
protected Logger log;
protected IRoutingService routingEngine;
protected IOFSwitchService switchEngine;
protected IFloodlightProviderService floodlightProvider;
protected Map<MacAddress, SwitchPort> mac_to_switchport;
3.在getModuleDependencies⽅法中告诉Floodlight这个类将依赖IFloodlightProviderService类:
@Override// IFloodlightModule
public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>();
l.add(IFloodlightProviderService.class);
return l;
}
4.初始化定义的变量,通过ServiceImpl()⽅法从context中获得需要的类并赋值给这些全局变量
@Override// IFloodlightModule
红十字国际委员会的创始人是?
public void init(FloodlightModuleContext context) throws FloodlightModuleException {
floodlightProvider = ServiceImpl(IFloodlightProviderService.class);
银监会routingEngine = ServiceImpl(IRoutingService.class);
switchEngine = ServiceImpl(IOFSwitchService.class);
log = Logger("TransHttpProxyDemo");
mac_to_switchport = new HashMap<MacAddress, SwitchPort>();
}
5.为了能获得Switch中实际传输的,启动阶段使floodlightProvider监听传⼊控制器的PACKET_IN包,当switch收到⼀条需转发的以太⽹帧(Ethernet)但是却⽆法匹配⽬前的转发表时,会将构建⼀种PACKET_IN类型的Openflow包交给控制器请求处理,这时,我们能通过调⽤floodlightProvider变量中的⽅法来获取switch中这个实际的以太⽹帧
@Override// IFloodlightModule输液泵
public void startUp(FloodlightModuleContext context) {
floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
}
6.下⾯我们编写receive⽅法来对控制器收到的每个PACKET_IN包进⾏处理:
@Override
public IListener.Command receive(IOFSwitch sw, OFMessage msg,
FloodlightContext cntx) {
// ⾸先确认收到msg的类型为PACKET_IN
if (Type() != OFType.PACKET_IN) {
return Command.CONTINUE;
}
/
/ 取出以太帧eth并确认以太帧中的载荷为Ipv4类型的数据报
OFPacketIn pki = (OFPacketIn) msg;
Ethernet eth = (cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
IPacket p = Payload();
if (!(p instanceof IPv4)) {
return Command.CONTINUE;
}
// 获得这个eth传⼊switch时的⽹络适配器端⼝,注意由于Floodlight版本不同因此获得⽅式有所不同
OFPort in_port = (Version()pareTo(OFVersion.OF_12) < 0) ? InPort()高通滤波器设计
: Match().get(MatchField.IN_PORT);
// 获得这个eth在swith中缓存队列中的id
OFBufferId bufid = BufferId();
// 获得这个eth的源Mac地址和⽬的Mac地址
MacAddress dl_src = SourceMACAddress();
MacAddress dl_dst = DestinationMACAddress();
// 如果⽬的地址匹配调试Mac地址,则发送丢包指令,并储存这个eth的源MAC地址和SwitchPort
雪铁龙c3 picassoif (dl_dst.equals(MAGIC)) {
SwitchPort tmp = new Id(), in_port);
mac_to_switchport.put(dl_src, tmp);
send_drop_rule(tmp, bufid, dl_src, dl_dst);
return Command.STOP;
}
/
/ 调⽤process_pkt⽅法处理
process_pkt(sw, in_port, bufid, dl_src, dl_dst);
return Command.STOP;
}
Note: 引⼊调试Mac地址的⽬的是,将所有尝试向调试Mac地址发送包的主机的Mac地址和与之连接的switch及端⼝储存在mac_to_switchport,这样能够事先掌握所有主机与和与之连接的switch信息,以便后⾯建⽴各个host之间的转发渠道
7.对于继续处理的以太帧eth,编写process_pkt⽅法进⼀步处理

本文发布于:2024-09-23 10:21:41,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/181780.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议