暑期实训的第一个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 Mininet
from mininet.cli import CLI
from mininet.node import RemoteController,Controller
from mininet.log import info
import sys

if len(sys.argv) == 1:
controller_ip = '127.0.0.1'
else:
controller_ip = sys.argv[1]

# net = Mininet(controller=Controller)
# controller=net.addController(ip='127.0.0.1',port=6653)
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 base64
import json
import httplib
import time
import math
from threading import Timer
import random
import sys

def 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,
# 'hard-timeout':'5'
'priority': "200"
}

#match
# match_set = {'in-port':switch_id+':23'}
ethernet_match ={'ethernet-type':{'type':"2048"}}
match_set = {
'ethernet-match':ethernet_match,
'ipv4-destination':'10.0.0.2/32'
}

#action
# action_set = {
# 'order': "0",
# 'output-action':{"output-node-connector": switch_id +':' + port }
# }
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)
# print(port_flag)
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地址是否发生变化。