Passed
Pull Request — master (#235)
by Aldo
03:37
created

002_recover_vlans.get_cookie()   A

Complexity

Conditions 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
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]]:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
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')]
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable controller does not seem to be defined.
Loading history...
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 (
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
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