-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathdp.py
More file actions
205 lines (176 loc) · 7.76 KB
/
Copy pathdp.py
File metadata and controls
205 lines (176 loc) · 7.76 KB
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# Copyright (C) 2015 Brad Cowie, Christopher Lorier and Joe Stringer.
# Copyright (C) 2015 Research and Education Advanced Network New Zealand Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import copy
import logging
import yaml
from vlan import VLAN
from port import Port
class DP(object):
"""Object to hold the configuration for a faucet controlled datapath."""
dp_id = None
acls = None
vlans = None
ports = None
running = False
influxdb_stats = False
def __init__(self, dp_id, logname):
self.dp_id = dp_id
self.acls = {}
self.vlans = {}
self.ports = {}
self.mirror_from_port = {}
self.acl_in = {}
self.logger = logging.getLogger(logname)
self.set_defaults()
@classmethod
def parser(cls, config_file, logname=__name__):
logger = logging.getLogger(logname)
try:
with open(config_file, 'r') as stream:
conf = yaml.load(stream)
except yaml.YAMLError as ex:
mark = ex.problem_mark
errormsg = "Error in file: {0} at ({1}, {2})".format(
config_file,
mark.line + 1,
mark.column + 1)
logger.error(errormsg)
return None
if 'dp_id' not in conf:
errormsg = "dp_id not configured in file: {0}".format(config_file)
logger.error(errormsg)
return None
dp = DP(conf['dp_id'], logname)
interfaces = conf.pop('interfaces', {})
vlans = conf.pop('vlans', {})
acls = conf.pop('acls', {})
dp.__dict__.update(conf)
dp.set_defaults()
for vid, vlan_conf in vlans.iteritems():
dp.add_vlan(vid, vlan_conf)
for port_num, port_conf in interfaces.iteritems():
dp.add_port(port_num, port_conf)
for acl_num, acl_conf in acls.iteritems():
dp.add_acl(acl_num, acl_conf)
return dp
def sanity_check(self):
assert 'dp_id' in self.__dict__
assert isinstance(self.dp_id, int)
for vid, vlan in self.vlans.iteritems():
assert isinstance(vid, int)
assert isinstance(vlan, VLAN)
assert all(isinstance(p, Port) for p in vlan.get_ports())
for portnum, port in self.ports.iteritems():
assert isinstance(portnum, int)
assert isinstance(port, Port)
assert isinstance(self.monitor_ports, bool)
assert isinstance(self.monitor_ports_file, basestring)
assert isinstance(self.monitor_ports_interval, int)
assert isinstance(self.monitor_flow_table, bool)
assert isinstance(self.monitor_flow_table_file, basestring)
assert isinstance(self.monitor_flow_table_interval, int)
assert isinstance(self.influxdb_stats, bool)
def set_defaults(self):
# Offset for tables used by faucet
self.__dict__.setdefault('table_offset', 0)
# The table for internally associating vlans
self.__dict__.setdefault('vlan_table', self.table_offset)
# Table for applying ACLs.
self.__dict__.setdefault('acl_table', self.table_offset + 1)
# The table for checking eth src addresses are known
self.__dict__.setdefault('eth_src_table', self.table_offset + 2)
# The table for matching eth dst and applying unicast actions
self.__dict__.setdefault('eth_dst_table', self.table_offset + 3)
# The table for applying broadcast actions
self.__dict__.setdefault('flood_table', self.table_offset + 4)
# How much to offset default priority by
self.__dict__.setdefault('priority_offset', 0)
# Some priority values
self.__dict__.setdefault('lowest_priority', self.priority_offset)
self.__dict__.setdefault('low_priority', self.priority_offset + 9000)
self.__dict__.setdefault('high_priority', self.low_priority + 1)
self.__dict__.setdefault('highest_priority', self.high_priority + 98)
# Identification cookie value to allow for multiple controllers to
# control the same datapath
self.__dict__.setdefault('cookie', 1524372928)
# inactive MAC timeout
self.__dict__.setdefault('timeout', 300)
# enable port stats monitoring?
self.__dict__.setdefault('monitor_ports', False)
# File for port stats logging
self.__dict__.setdefault('monitor_ports_file', 'logfile.log')
# Stats reporting interval (in seconds)
self.__dict__.setdefault('monitor_ports_interval', 30)
# Enable flow table monitoring?
self.__dict__.setdefault('monitor_flow_table', False)
# File for flow table logging
self.__dict__.setdefault('monitor_flow_table_file', 'logfile.log')
# Stats reporting interval
self.__dict__.setdefault('monitor_flow_table_interval', 30)
# Name for this dp, used for stats reporting
self.__dict__.setdefault('name', str(self.dp_id))
# description, strictly informational
self.__dict__.setdefault('description', self.name)
# The hardware maker (for chosing an openflow driver)
self.__dict__.setdefault('hardware', 'Open_vSwitch')
# Whether to use influxdb for stats
self.__dict__.setdefault('influxdb_stats', False)
# ARP and neighbor timeout (seconds)
self.__dict__.setdefault('arp_neighbor_timeout', 500)
# OF channel log
self.__dict__.setdefault('ofchannel_log', None)
def add_acl(self, acl_num, acl_conf=None):
if acl_conf is not None:
self.acls[acl_num] = [x['rule'] for x in acl_conf]
def add_port(self, port_num, port_conf=None):
# add port specific vlans or fall back to defaults
port_conf = copy.copy(port_conf) if port_conf else {}
port = self.ports.setdefault(port_num, Port(port_num, port_conf))
port_conf.setdefault('mirror', None)
if port_conf['mirror'] is not None:
from_port_num = port_conf['mirror']
self.mirror_from_port[from_port_num] = port_num
# other configuration entries ignored.
return
# add native vlan
port_conf.setdefault('native_vlan', None)
if port_conf['native_vlan'] is not None:
vid = port_conf['native_vlan']
if vid not in self.vlans:
self.vlans[vid] = VLAN(vid)
self.vlans[vid].untagged.append(self.ports[port_num])
# add vlans
port_conf.setdefault('tagged_vlans', [])
for vid in port_conf['tagged_vlans']:
if vid not in self.vlans:
self.vlans[vid] = VLAN(vid)
self.vlans[vid].tagged.append(port)
# add ACL
port_conf.setdefault('acl_in', None)
if port_conf['acl_in'] is not None:
self.acl_in[port_num] = port_conf['acl_in']
def add_vlan(self, vid, vlan_conf=None):
vlan_conf = copy.copy(vlan_conf) if vlan_conf else {}
self.vlans.setdefault(vid, VLAN(vid, vlan_conf))
def get_native_vlan(self, port_num):
if port_num not in self.ports:
return None
port = self.ports[port_num]
for vlan in self.vlans.values():
if port in vlan.untagged:
return vlan
return None
def __str__(self):
return "name={0}, id={1}".format(self.name, self.id)