1
|
|
|
from collections import defaultdict |
2
|
|
|
from kytos.core.tag_ranges import range_difference |
3
|
|
|
|
4
|
|
|
# Change to False so this script makes changes |
5
|
|
|
DRY_RUN = True |
6
|
|
|
# Modify with VLAN used in of_lldp |
7
|
|
|
OF_LLDP_VLAN = 3799 |
8
|
|
|
# Change to False to not print the missing VLANs |
9
|
|
|
PRINT_MISSING = True |
10
|
|
|
REMOVE_LLDP_FLOWS = False |
11
|
|
|
|
12
|
|
|
def get_cookie(dpid): |
13
|
|
|
"""Return the cookie integer given a dpid.""" |
14
|
|
|
COOKIE_PREFIX = 0xab |
15
|
|
|
return (0x0000FFFFFFFFFFFF & int(dpid.replace(":", ""), 16) | (COOKIE_PREFIX << 56)) |
16
|
|
|
|
17
|
|
|
def send_flows(dpid, cookie): |
18
|
|
|
import httpx |
19
|
|
|
FLOW_MANAGER_URL = 'http://localhost:8181/api/kytos/flow_manager/v2' |
20
|
|
|
url = f"{FLOW_MANAGER_URL}/flows/{dpid}" |
21
|
|
|
data = {"flows": [{ |
22
|
|
|
"cookie": cookie, |
23
|
|
|
"cookie_mask": int(0xFFFFFFFFFFFFFFFF), |
24
|
|
|
}], "force": True} |
25
|
|
|
res = httpx.request("DELETE", url, json=data, timeout=10) |
26
|
|
|
if res.is_server_error or res.status_code in {424, 404, 400}: |
27
|
|
|
print(f"Error deleting LLDP flows from Switch {dpid}: {res.text}") |
28
|
|
|
|
29
|
|
View Code Duplication |
def get_range(vlans, avoid) -> list[list[int]]: |
|
|
|
|
30
|
|
|
"""Convert available_vlans to available_tags. |
31
|
|
|
From list[int] to list[list[int]]""" |
32
|
|
|
result = [] |
33
|
|
|
if not vlans: |
34
|
|
|
return result |
35
|
|
|
vlans.sort() |
36
|
|
|
i = 0 |
37
|
|
|
while i < len(vlans): |
38
|
|
|
if vlans[i] in avoid: |
39
|
|
|
i += 1 |
40
|
|
|
else: |
41
|
|
|
break |
42
|
|
|
if not vlans[i:]: |
43
|
|
|
return result |
44
|
|
|
|
45
|
|
|
start = end = vlans[i] |
46
|
|
|
for tag in vlans[i+1:]: |
47
|
|
|
if tag in avoid: |
48
|
|
|
continue |
49
|
|
|
if tag == end + 1: |
50
|
|
|
end = tag |
51
|
|
|
else: |
52
|
|
|
result.append([start, end]) |
53
|
|
|
start = end = tag |
54
|
|
|
result.append([start, end]) |
55
|
|
|
return result |
56
|
|
|
|
57
|
|
|
mef_eline = controller.napps[('kytos', 'mef_eline')] |
|
|
|
|
58
|
|
|
evcs = {evc_id: evc.as_dict() for evc_id, evc in mef_eline.circuits.items() if not evc.archived} |
59
|
|
|
|
60
|
|
|
in_use_tags = defaultdict(set) |
61
|
|
|
for evc_id, evc in evcs.items(): |
62
|
|
|
for link in evc["current_path"]: |
63
|
|
|
svlan = link["metadata"]["s_vlan"]["value"] |
64
|
|
|
intfa = link["endpoint_a"]["id"] |
65
|
|
|
intfb = link["endpoint_b"]["id"] |
66
|
|
|
in_use_tags[intfa].add(svlan) |
67
|
|
|
in_use_tags[intfb].add(svlan) |
68
|
|
|
for link in evc["failover_path"]: |
69
|
|
|
svlan = link["metadata"]["s_vlan"]["value"] |
70
|
|
|
intfa = link["endpoint_a"]["id"] |
71
|
|
|
intfb = link["endpoint_b"]["id"] |
72
|
|
|
in_use_tags[intfa].add(svlan) |
73
|
|
|
in_use_tags[intfb].add(svlan) |
74
|
|
|
for uni in ("uni_a", "uni_z"): |
75
|
|
|
intf_id = evc[uni]["interface_id"] |
76
|
|
View Code Duplication |
if ( |
|
|
|
|
77
|
|
|
"tag" in evc[uni] |
78
|
|
|
and evc[uni]["tag"] |
79
|
|
|
and "tag_type" in evc[uni]["tag"] |
80
|
|
|
and evc[uni]["tag"]["tag_type"] in ("vlan", 1) |
81
|
|
|
): |
82
|
|
|
tag = evc[uni]["tag"]["value"] |
83
|
|
|
if isinstance(tag, int): |
84
|
|
|
in_use_tags[intf_id].add(tag) |
85
|
|
|
elif isinstance(tag, list): |
86
|
|
|
for tag_item in tag: |
87
|
|
|
if isinstance(tag_item, int): |
88
|
|
|
in_use_tags[intf_id].add(tag_item) |
89
|
|
|
elif isinstance(tag_item, list) and len(tag_item) == 1: |
90
|
|
|
in_use_tags[intf_id].add(tag_item[0]) |
91
|
|
|
elif isinstance(tag_item, list) and len(tag_item) == 2: |
92
|
|
|
for val in range(tag_item[0], tag_item[1]+1): |
93
|
|
|
in_use_tags[intf_id].add(val) |
94
|
|
|
|
95
|
|
|
switch_rm_flows = {} |
96
|
|
|
for dpid in list(controller.switches.keys()): |
97
|
|
|
switch = controller.get_switch_by_dpid(dpid) |
98
|
|
|
of_lldp_cookie = get_cookie(switch.id) |
99
|
|
|
of_lldp_flow = False |
100
|
|
|
for flow in switch.flows.copy(): |
101
|
|
|
if of_lldp_cookie == flow.cookie: |
102
|
|
|
of_lldp_flow = True |
103
|
|
|
break |
104
|
|
|
if not switch.is_enabled() and of_lldp_flow: |
105
|
|
|
print(f"WARNING -> Switch {dpid} is disabled and has LLDP flows.") |
106
|
|
|
if REMOVE_LLDP_FLOWS: |
107
|
|
|
switch_rm_flows[dpid] = of_lldp_cookie |
108
|
|
|
|
109
|
|
|
for interface in switch.interfaces.copy().values(): |
110
|
|
|
intf_id = interface.id |
111
|
|
|
vlans = in_use_tags.get(intf_id, set()) |
112
|
|
|
if OF_LLDP_VLAN and switch.is_enabled() and of_lldp_flow: |
113
|
|
|
vlans.add(OF_LLDP_VLAN) |
114
|
|
|
vlans = get_range(sorted(list(vlans)), set()) |
115
|
|
|
intf = controller.get_interface_by_id(intf_id) |
116
|
|
|
tag_range = intf.tag_ranges["vlan"] |
117
|
|
|
available_tags = range_difference(tag_range, vlans) |
118
|
|
|
if intf.available_tags["vlan"] != available_tags: |
119
|
|
|
print(f"Missing available tags in interface {intf_id}:\n" |
120
|
|
|
f"WRONG -> {intf.available_tags['vlan']}\n" |
121
|
|
|
f"CORRECT -> {available_tags}") |
122
|
|
|
if PRINT_MISSING: |
123
|
|
|
print(f"MISSING -> {range_difference(available_tags, intf.available_tags['vlan'])}") |
124
|
|
|
if not DRY_RUN: |
125
|
|
|
intf.make_tags_available(controller, available_tags, 'vlan') |
126
|
|
|
print("\n") |
127
|
|
|
|
128
|
|
|
# Removing flows if REMOVE_LLDP_FLOWS is True |
129
|
|
|
for dpid, cookie in switch_rm_flows.items(): |
130
|
|
|
send_flows(dpid, cookie) |
131
|
|
|
|