aboutsummaryrefslogtreecommitdiffstats
path: root/vicn/resource/ns3/emulated_wifi_channel.py
blob: 088d44446292333e3eb6f95daf27b5a907cb30a8 (plain)
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
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 Cisco and/or its affiliates.
#
# 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.
#

from vicn.resource.ns3.emulated_channel import EmulatedChannel
from vicn.resource.linux.net_device     import NetDevice
from vicn.core.address_mgr              import AddressManager
from vicn.core.resource_mgr             import wait_resources
from vicn.core.task                     import async_task, run_task

class EmulatedWiFiChannel(EmulatedChannel):
    """EmulatedWiFiChannel Resource

    This resource uses the ns3 simulator to emulate an 80211n wireless channel.
    It assume no interference between base stations, and thus the emulated
    channel corresponds to a single base station.
    """
    __package_names__ = ['wifi-emulator']
    __app_name__ = 'wifi_emulator'

    #---------------------------------------------------------------------------
    # Attribute handlers
    #---------------------------------------------------------------------------

    async def _add_station(self, station):
        from vicn.resource.lxd.lxc_container    import LxcContainer
        from vicn.resource.linux.veth_pair      import VethPair
        from vicn.resource.linux.tap_device     import TapChannel
        from vicn.resource.linux.macvlan        import MacVlan

        interfaces = list()
        if not station.managed:
            sta_if = None
        else:
            if isinstance(station, LxcContainer):
                host = NetDevice(node = station.node,
                    device_name='vhh-' + station.name + '-' + self.name,
                    managed = False)
                sta_if = VethPair(node = station,
                        name          = 'vh-' + station.name + '-' + self.name,
                        device_name   = 'vh-' + station.name + '-' + self.name, 
                        host          = host,
                        owner = self)
                bridged_sta = sta_if.host
            else:
                raise NotImplementedError 

        if sta_if:
            self._sta_ifs[station] = sta_if
            self._sta_bridged[station] = bridged_sta
            interfaces.append(sta_if)
            self._state.manager.commit_resource(sta_if)

        sta_tap = TapChannel(node = self.node, 
                owner = self,
                device_name = 'tap-' + station.name + '-' + self.name,
                up = True,
                promiscuous = True,
                station_name = station.name,
                channel_name = self.name)
        self._sta_taps[station] = sta_tap
        interfaces.append(sta_tap)
        self._state.manager.commit_resource(sta_tap)

        # Wait for interfaces to be setup
        await wait_resources(interfaces)

        # Add interfaces to bridge
        # One vlan per station is needed to avoid broadcast loops
        vlan = AddressManager().get('vlan', sta_tap) 
        # sta_tap choosen because always there
        if sta_if:
            sta_if.set('channel', self)

            task = self.node.bridge._remove_interface(bridged_sta)
            await run_task(task, self._state.manager)
            task = self.node.bridge._add_interface(bridged_sta,
                    vlan = vlan)
            await run_task(task, self._state.manager)

        task = self.node.bridge._add_interface(sta_tap, vlan = vlan)
        await run_task(task, self._state.manager)


    def _get_cmdline_params(self, ):

        # sta-macs and sta-list for unmanaged stations
        sta_list = list() # list of identifiers
        sta_macs = list() # list of macs
        sta_taps = list()
        for station in self.stations:
            if not station.managed:
                interface = [i for i in station.interfaces if i.channel == self]
                assert len(interface) == 1
                interface = interface[0]

                sta_list.append(interface.name)
                sta_macs.append(interface.mac_address)
            else:
                identifier = self._sta_ifs[station]._state.uuid._uuid
                sta_list.append(identifier)

                mac = self._sta_ifs[station].mac_address
                sta_macs.append(mac)

            tap = self._sta_taps[station].device_name
            sta_taps.append(tap)

        params = {
            # Name of the tap between NS3 and the base station
            'bs-tap'        : self._ap_tap.device_name,
            # Number of stations
            'n-sta'         : len(self._sta_taps),
            # List of the stations of the simulation # identifiers
            'sta-list'      : ','.join(sta_list),
            # List of the taps between NS3 and the mobile stations
            'sta-taps'      : ','.join(sta_taps),
            # List of the macs of the mobile stations
            'sta-macs'      : ','.join(sta_macs),
            # X position of the Base Station
            'bs-x'          : 0, #self.ap.x,
            # Y position of the Base Station
            'bs-y'          : 0, #self.ap.y,
            # Experiment ID
            'experiment-id' : 'vicn', 
            # Index of the base station
            'bs-name'       : self._ap_tap.device_name,
            # Base station MAC address
            'bs-mac'        : self._ap_if.mac_address,
            # Control port for dynamically managing the stations movement
            'control-port'  : self.control_port,
        }

        return ' '.join(['--{}={}'.format(k, v) for k, v in params.items()])