Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Основы программно-конфигурируемых сетей. Учебное пособие
.pdf
OSP
Начало
Входные
данные
D[f0] – максимальная задержка для расчетного потока
R[f0] – минимальная полоса пропускания для расчетного потока
R[fi] – минимальная полоса пропускания для остальных потоков
Q – приоритет расчетного потока, IP источника, IP Приемника
C – максимально доступная пропускная способностьспособность
Построение графа
Вычисление
остаточной
пропускной
способности
Arf=C-S
A
i
<
length
(
Rf
)
S
=
S
+
Rf
[
i
]
i
=
i
+
1
i
=
1
S
=
0
A
j
=
1
R
[
j
:
8
]
=
S
Low
[
f
0
]
=
0
Hi
[
f
0
]
=
8
А
Рисунок А.3 – Алгоритм выбора оптимального сочетания приоритетов
101

R[f0]<=Arf
Df=f(Q,R[j:8],C)
Df<D[f0]
Расчет оптимального
пути
B
j
<
=
Q
Df[
0
]=
D
[
f
0
]*
0
,
95
Low
=
Hi
R
[f0
]=
R
[
Hi
:
8
]
R
[
j
:
8
]
=
R
[
j:8
]
-
R
[
fj
]
R[
f
0
]=
Rf
[
0
]*
0
,
95
Приоритет R[f0] > приоритета D[f0]?
Route
j
=
j
+
1
Low[f0]=0
Low
[f0
]
=
j
Df>=D[f0]
Hi
[
f
0
]
=
j
да
да
Low[f0]=0
да
Расчет оптимального
пути
Route
B
Df=f(Q,R[j:8],C)
Df<D[f0] И
Rf[0]<=R[Low:8]
C
j
<
=
Q
D[
f
0
]=D
[
f
0
]*
0
,
95
R[
j
:
8
]
=
R
[
j
:
8
]
-
R
[
fj
]
j
=
j
+
1
Low[f0]=0
Low
[
f
0
]
=
j
Df>=D[f0]
Hi
[f0
]
=
j
да
Low[f0]=0
да
C
Hi[f0]=8
да
нет
нет
да
нет
да
нет
нет
нет
нет
нет
да
нет
да
да
нет
нет
А
В
Продолжение рисунка А.3
102

OSP
Конец
D
i
<
Количества
коммутаторов
Вычисление
G
[
i
]
,
INP
[i]
,
OUT
[
i
]
i
=
0
Gi=Подграф пути (порты) с
коммутатором i
INPi=Входящие порты из Gi
OUTi=Исходящие порты из Gi
Match_Gi=Список портов из
INPi
Match_Gi=Match_Gi+ IP
адреса
Action_Gi=(Исходящий порт=OUTi)
Action_Gi = (Приоритет=Low)
i=i+1
D
В
Продолжение рисунка А.3
Сведения об очередях и загрузках периодически программой MRTG по
протоколу SNMP загружаются из коммутатора и помещаются в БД MRTG.
Коммутатор проверяет свою таблицу потоков, и если соответствующая запись
не обнаружена, то коммутатор посылает пакет в контроллер NOX. NOX
преобразует пакет в объекты, заполняет их и передает своим подключенным
модулям для коммутации (pyswitch). Модуль Pyswitch проверяет в
соответствующем списке наличие совпадений. Если совпадения найдены, то
соответствующие записи OpenFlow передаются коммутатору, иначе
направляется запрос в модуль QoS, который посылает запрос о наличии
соответствующей записи в БД интерфейса управления системой. Если запись
не найдена, то управление передается pyswitcg, который просто выполняет
коммутацию. Если же запись существует, то модуль QoS вызывает алгоритм
нахождения оптимальных параметров. На выходе получается набор правил для
каждого коммутатора в топологии. Эти правила передаются в модуль pyswitch,
который устанавливает их во все доступные коммутаторы.
103

Для вызова программы необходимо скопировать файл прототипа модуля
QoS в папку nox/src/nox/netapps/qos. Туда же необходимо скопировать файлы
makefile.am и meta.json из папки nox/src/nox/apps/examples. Затем в файле
nox/configure.ac.in необходимо найти строку «ACI_PACKAGE([netapps],» и
добавить в конец имя модуля «qos,» (запятую ставить обязательно). Затем в
папке nox необходимо выполнить команду gmake&&make.
Для запуска nox с модулем qos необходимо перйти в папку nox/src и
выполнить команду «./nox_core –v –iptcp:6633 qospyswitchtopology».
Новый класс обработчика пакетов OpenFlowl2-multy регистрируется в
классе core модуля OpenFlow. Входным методом из NOX в модуль qos является
метод ConnectionUp, возникающий при подключении нового коммутатора.
Обработчик пакетов направлен на стандартный метод packetIn класса Switch.
Входными данными для программы является информация из БД, которую
модуль объектно-реляционного отображения (ORM) преобразует в классы и
семейства классов, сведения из OpenFlow, которые NOX преобразует в
объектную модель, а также входные данные OpenFlow.
Выходными данными являются объекты OFP-match и OFP-action,
представленныев виде текстовой строки.
104

сетях
Приложение Б
Исходный код прототипа обеспечения QoS в ПКС
/* Название: Прототип средства обеспечения QoS в программно-конфигурируемых
*/
from django.core.management import setup_environ
from mysite import settings
setup_environ(settings)
from flew.models import Flow
from nox.core import core
import nox.openflow.libopenflow_01 as of
from nox.lib.revent import *
from collections import defaultdict
from nox.openflow.discovery import Discovery
from nox.lib.util import dpidToStr
import time
log = core.getLogger()
# Adjacency map. [sw1][sw2] -> port from sw1 to sw2
adjacency = defaultdict(lambda:defaultdict(lambda:None))
# Switches we know of. [dpid] -> Switch
switches = {}
# ethaddr -> (switch, port)
mac_map = {}
# [sw1][sw2] -> (distance, intermediate)
path_map = defaultdict(lambda:defaultdict(lambda:(None,None)))
FLOOD_HOLDDOWN = 5
def _calc_paths ():
"""
Essentially Floyd-Warshall algorithm
"""
sws = switches.values()
path_map.clear()
for k in sws:
for j,port in adjacency[k].iteritems():
if port is None: continue
path_map[k][j] = (1,None)
path_map[k][k] = (0,None) # промежуточное расстояние
"""
for i in sws:
105

for j in sws:
a = path_map[i][j][0]
if a is None: a = "*"
print a,
print
"""
for k in sws:
for i in sws:
for j in sws:
if path_map[i][k][0] is not None:
if path_map[k][j][0] is not None:
ikj_dist = path_map[i][k][0]+path_map[k][j][0]
if path_map[i][j][0] is None or ikj_dist < path_map[i][j][0]:
path_map[i][j] = (ikj_dist, k)
"""
print "--------------------"
for i in sws:
for j in sws:
print path_map[i][j][0],
print
"""
def _get_raw_path (src, dst):
if len(path_map) == 0: _calc_paths()
if src is dst:
# We're here!
return []
if path_map[src][dst][0] is None:
return None
intermediate = path_map[src][dst][1]
if intermediate is None:
# непосредственносвязаны
return []
return _get_raw_path(src, intermediate) + [intermediate] + \
_get_raw_path(intermediate, dst)
def _check_path (p):
for i in range(len(p) - 1):
if adjacency[p[i][0]][p[i+1][0]] != p[i][1]:
return False
return True
def _get_path (src, dst, final_port):
if src == dst:
path = [src]
else:
path = _get_raw_path(src, dst)
if path is None: return None
path = [src] + path + [dst]
r = []
for s1,s2 in zip(path[:-1],path[1:]):
port = adjacency[s1][s2]
106

r.append((s1,port))
r.append((dst, final_port))
assert _check_path(r)
return r
class PathInstalled (Event):
"""
Fired when a path is installed
"""
def __init__ (self, path):
Event.__init__(self)
self.path = path
class Switch (EventMixin):
def __init__ (self):
self.connection = None
self.ports = None
self.dpid = None
self._listeners = None
self._connected_at = None
for flow in Flow.objects.all():
self._AddFlowFromModel(flow)
def _AddFlowFromModel(self, flow):
# Добавление исходящего потока
msg = of.ofp_flow_mod()
msg.match = of.ofp_match()
msg.match.dl_type = ethernet.IP_TYPE
msg.match.nw_src = str(flow.internalip)
msg.match.nw_dst = str(flow.externalip)
msg.match.in_port = flow.internalport
msg.idle_timeout = flow.idletime
msg.hard_timeout = flow.hardtime
msg.actions.append(of.ofp_action_output(port = flow.externalport))
self.connection.send(msg)
# Добавление входящего потока
msg = of.ofp_flow_mod()
msg.match = of.ofp_match()
msg.match.dl_type = ethernet.IP_TYPE
msg.match.nw_src = str(flow.externalip)
msg.match.nw_dst = str(flow.internalip)
msg.match.in_port = flow.externalport
msg.idle_timeout = flow.idletime
msg.hard_timeout = flow.hardtime
msg.actions.append(of.ofp_action_output(port = flow.internalport))
self.connection.send(msg)
def __repr__ (self):
return dpidToStr(self.dpid)
107

def _install (self, switch, port, match, buf = None, pcp=None):
msg = of.ofp_flow_mod()
msg.match = match
msg.idle_timeout = 10
msg.hard_timeout = 30
msg.actions.append(of.ofp_action_output(port = port))
msg.buffer_id = buf
switch.connection.send(msg)
def _install_path (self, p, match, buffer_id = None):
for sw,port in p[1:]:
self._install(sw, port, match)
self._install(p[0][0], p[0][1], match, buffer_id)
core.l2_multi.raiseEvent(PathInstalled(p))
def install_path (self, dst_sw, last_port, match, event):#buffer_id, packet):
p = _get_path(self, dst_sw, last_port)
if p is None:
log.warning("Can't get from %s to %s", match.dl_src, match.dl_dst)
import nox.lib.packet as pkt
if (match.dl_type == pkt.ethernet.IP_TYPE and
event.parsed.find('ipv4')):
log.debug("Dest unreachable (%s -> %s)",
match.dl_src, match.dl_dst)
from nox.lib.addresses import EthAddr
e = pkt.ethernet()
e.src = EthAddr(dpidToStr(self.dpid))
e.dst = match.dl_src
e.type = e.IP_TYPE
ipp = pkt.ipv4()
ipp.protocol = ipp.ICMP_PROTOCOL
ipp.srcip = match.nw_dst
ipp.dstip = match.nw_src
icmp = pkt.icmp()
icmp.type = pkt.ICMP.TYPE_DEST_UNREACH
icmp.code = pkt.ICMP.CODE_UNREACH_HOST
orig_ip = event.parsed.find('ipv4')
d = orig_ip.pack()
d = d[:orig_ip.hl * 4 + 8]
import struct
d = struct.pack("!HH", 0,0) + d
icmp.payload = d
ipp.payload = icmp
e.payload = ipp
msg = of.ofp_packet_out()
108

msg.actions.append(of.ofp_action_output(port = event.port))
msg.data = e.pack()
self.connection.send(msg)
return
self._install_path(p, match, event.ofp.buffer_id)
log.debug("Installing path for %s -> %s %04x (%i hops)", match.dl_src, match.dl_dst,
match.dl_type, len(p))
def _handle_PacketIn (self, event):
def flood ():
""" Floods the packet """
if self.is_holding_down:
log.warning("Not flooding -- holddown active")
msg = of.ofp_packet_out()
msg.actions.append(of.ofp_action_output(port = of.OFPP_FLOOD))
msg.buffer_id = event.ofp.buffer_id
msg.in_port = event.port
self.connection.send(msg)
def drop ():
# Очисткабуфера
if event.ofp.buffer_id is not None:
msg = of.ofp_packet_out()
msg.buffer_id = event.ofp.buffer_id
event.ofp.buffer_id = None # Меткаобнуляется
msg.in_port = event.port
self.connection.send(msg)
packet = event.parsed
loc = (self, event.port)
oldloc = mac_map.get(packet.src)
if packet.effective_ethertype == packet.LLDP_TYPE:
drop()
return
if oldloc is None:
if packet.src.isMulticast() == False:
mac_map[packet.src] = loc # Learn position for ethaddr
log.debug("Learned %s at %s.%i", packet.src, loc[0], loc[1])
elif oldloc != loc:
if loc[1] not in adjacency[loc[0]].values():
log.debug("%s moved from %s.%i to %s.%i?", packet.src,
dpidToStr(oldloc[0].connection.dpid), oldloc[1],
dpidToStr( loc[0].connection.dpid), loc[1])
if packet.src.isMulticast() == False:
mac_map[packet.src] = loc # Learn position for ethaddr
log.debug("Learned %s at %s.%i", packet.src, loc[0], loc[1])
elif packet.dst.isMulticast() == False:
log.warning("Packet from %s arrived at %s.%i without flow",# -- dropping",
109

packet.src, dpidToStr(self.dpid), event.port)
if packet.dst.isMulticast():
log.debug("Flood multicast from %s", packet.src)
flood()
else:
if packet.dst not in mac_map:
log.debug("%s unknown -- flooding" % (packet.dst,))
flood()
else:
dest = mac_map[packet.dst]
match = of.ofp_match.from_packet(packet)
self.install_path(dest[0], dest[1], match, event)
def disconnect (self):
if self.connection is not None:
log.debug("Disconnect %s" % (self.connection,))
self.connection.removeListeners(self._listeners)
self.connection = None
self._listeners = None
def connect (self, connection):
if self.dpid is None:
self.dpid = connection.dpid
assert self.dpid == connection.dpid
if self.ports is None:
self.ports = connection.features.ports
self.disconnect()
log.debug("Connect %s" % (connection,))
self.connection = connection
self._listeners = self.listenTo(connection)
self._connected_at = time.time()
@property
def is_holding_down (self):
if self._connected_at is None: return True
if time.time() - self._connected_at > FLOOD_HOLDDOWN:
return False
return True
def _handle_ConnectionDown (self, event):
self.disconnect()
pass
class l2_multi (EventMixin):
_eventMixin_events = set([
PathInstalled,
])
def __init__ (self):
self.listenTo(core.openflow, priority=0)
self.listenTo(core.openflow_discovery)
def _handle_LinkEvent (self, event):
def flip (link):
return Discovery.Link(link[2],link[3], link[0],link[1])
l = event.link
110
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
