暑期实训的第一个SDN项目。
0x01 实验要求:
在生活中遇到这样的场景,对Server的性能要求很高;但无论再好的硬件,也有力不足的时候,特别是还可能遇到宕机的时候:(不得不吐槽一下某语言等级考试报名网站 凸(艹皿艹) )
如上图的服务器部署,就能有效减少上述情况;所以负载均衡在现实生活中很有必要。
0x02 网络拓扑
网络拓扑很简单,就如下图所示。由控制器下发流表,实现h3、h4分担h2服务的压力。
提供网络拓扑构建的源码:基于Mininet的拓扑构建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 from mininet.net import Mininetfrom mininet.cli import CLIfrom mininet.node import RemoteController,Controllerfrom mininet.log import infoimport sysif len (sys.argv) == 1 : controller_ip = '127.0.0.1' else : controller_ip = sys.argv[1 ] net = Mininet(controller=RemoteController) odl_controller=net.addController('ODL_controller' , controller=RemoteController, ip=controller_ip,port=6633 ) print ("*** Add Switch\n" )s1=net.addSwitch('s1' ) print ("*** Add Hosts\n" )h1=net.addHost('h1' ) print ("*** Addd Servers\n" )server1 = net.addHost('server1' ) server2 = net.addHost('server2' ) server3 = net.addHost('server3' ) net.addLink(s1,h1) net.addLink(s1,server1) net.addLink(s1,server2) net.addLink(s1,server3) h1.setIP('10.0.0.1' ,24 ) h1.setMAC('00:00:00:00:00:01' ) server1.setIP('10.0.0.2' ,24 ) server2.setIP('10.0.0.3' ,24 ) server3.setIP('10.0.0.4' ,24 ) server1.setMAC('00:00:00:00:00:02' ) server2.setMAC('00:00:00:00:00:03' ) server3.setMAC('00:00:00:00:00:04' ) net.start() CLI(net)
提前运行ODL控制器,命令行再运行:# python mytopo.py
;回到ODL控制器查看拓扑如下:
0x03 流表下发:
我们是通过编写python脚本实现流表的下发,以达到修改数据包信息的目的,从而实现转发至server2(h3)和sever3(h4)的目的。关键部分就是 macth_set和action的编写 。
流表的脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 import base64import jsonimport httplibimport timeimport mathfrom threading import Timerimport randomimport sysdef pre_put (url, body ): try : auth = base64.b64encode('admin:admin' .encode()) headers = {"Authorization" : "Basic " + auth, "Content-Type" : "application/json" } conn = httplib.HTTPConnection('127.0.0.1:8181' , timeout=3 ) conn.request("PUT" , url, body, headers) response = conn.getresponse() if response.status in [200 ,201 ]: print 'add success' else : print 'add failure' except Exception as e: import traceback traceback.print_exc() def add_flow (port,ip,mac ): switch_id = 'openflow:1' url = "/restconf/config/opendaylight-inventory:nodes/node/" + switch_id + "/flow-node-inventory:table/0/flow/5" flow_set = { 'id' : '5' , 'flow-name' : '5' , 'table_id' : 0 , 'priority' : "200" } ethernet_match ={'ethernet-type' :{'type' :"2048" }} match_set = { 'ethernet-match' :ethernet_match, 'ipv4-destination' :'10.0.0.2/32' } action_mod_mac={ 'order' :"0" , 'set-dl-dst-action' :{'address' :mac} } action_mod_ip = { 'order' :"1" , 'set-nw-dst-action' :{'ipv4-address' :ip} } action_set = { 'order' :"2" , 'output-action' :{"output-node-connector" :switch_id+':' +port} } instruc_set = { "instruction" : [{ "order" : "0" , "apply-actions" : { "action" : [action_mod_mac,action_mod_ip,action_set] } }] } flow_set['match' ] = match_set flow_set['instructions' ] = instruc_set body = json.dumps({"flow" :flow_set}) pre_put(url, body) def flow_change (s1_node_id ): port_flag = random.randint(0 ,2 ) if port_flag == 0 : port = '2' ip = '10.0.0.2/32' mac = '00:00:00:00:00:02' elif port_flag == 1 : port = '3' ip = '10.0.0.3/32' mac = '00:00:00:00:00:03' elif port_flag == 2 : port = '4' ip = '10.0.0.4/32' mac = '00:00:00:00:00:04' add_flow(port,ip,mac) print ("backend server is:server%s" %ip) if __name__=="__main__" : while True : flow_change('1' ) time.sleep(5 )
0x04 运行结果
从上图可以看到IP地址的变化。
**踩坑:**可能由于系统的原因,IP地址的变化不会在Shell中实时更新,可以通过wireshark抓包看一下,IP地址是否发生变化。