aboutsummaryrefslogtreecommitdiffstats
path: root/vicn/resource/vpp/vpp_bridge.py
blob: 612145d9246694055dcc6f54241919cf79ee63ce (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
#!/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 netmodel.model.type                import Integer
from vicn.core.attribute                import Attribute, Multiplicity
from vicn.core.attribute                import Reference
from vicn.core.exception                import ResourceNotFound
from vicn.core.requirement              import Requirement
from vicn.core.resource_mgr             import wait_resource_task
from vicn.core.resource                 import Resource
from vicn.core.task                     import task, BashTask, EmptyTask
from vicn.resource.channel              import Channel
from vicn.resource.linux.application    import LinuxApplication
from vicn.resource.linux.sym_veth_pair  import SymVethPair
from vicn.resource.linux.sym_veth_pair  import SymVethPair
from vicn.resource.node                 import Node
from vicn.resource.vpp.dpdk_device      import DpdkDevice
from vicn.resource.vpp.interface        import VPPInterface
from vicn.resource.vpp.vpp              import VPP

CMD_ADD_INTERFACE_TO_BR = ('vppctl set interface l2 bridge '
        '{interface.device_name} {br_domain}')

class VPPBridge(Channel, LinuxApplication):
    """
    Resource: VPPBridge

    VPPBridge instantiate a vpp resource and set it as a vpp bridge.

    This resource requires to be run within a LxcContainer which will have VPP.
    Every interface in the lxc_container (i.e., the ones contained in
    self.node.interfaces) will be added to the vpp bridge. To connect other vpp
    node to the bridge, the corresponding dpdkdevice must be added as an
    interface to the channel.
    """

    # The vpp bridge _USES_ a VPP forwarder on the node
    node = Attribute(Node, mandatory=True,
                     description = 'Node on which vpp is running',
                     requirements = [Requirement('vpp')])

    connected_nodes = Attribute(Node, multiplicity = Multiplicity.OneToMany,
                     description = 'List of nodes to connect to the bridge')

    #--------------------------------------------------------------------------
    # Constructor and Accessors
    #--------------------------------------------------------------------------

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._vpp_interfaces = list()

    #--------------------------------------------------------------------------
    # Resource lifecycle
    #--------------------------------------------------------------------------

    def __subresources__ (self):
        # We don't need any reference to the list of SymVethPair because each
        # side of a veth will be included in the node.interfaces list
        self._veths = [SymVethPair(node1 = self.node, node2 = node,
                owner = self) for node in self.connected_nodes]

        return Resource.__concurrent__(*self._veths)

    @task
    def __initialize__ (self):
        # Add the veth side on the connected_nodes to the set of interfaces of
        # the channel
        self.interfaces.extend([veth.side2 for veth in self._veths])

    @task
    def __get__(self):
        # Forces creation
        raise ResourceNotFound

    # Nothing to do
    __delete__ = None

    def __create__(self):
        manager = self._state.manager

        # Create a VPPInterface for each interface in the node. These will be
        # the interfaces we will connect to the vpp bridge process
        vpp_interfaces = list()
        for interface in self.node.interfaces:
            # FIXME harcoded value
            if interface.device_name == 'eth0':
                continue

            vpp_interface = VPPInterface(vpp = self.node.vpp,
                    parent = interface,
                    ip4_address = Reference(interface, 'ip4_address'),
                    device_name = 'host-' + interface.device_name)
            vpp_interfaces.append(vpp_interface)
            manager.commit_resource(vpp_interface)

        tasks = EmptyTask()

        for vpp_interface in vpp_interfaces:
            tasks = tasks > (wait_resource_task(vpp_interface) >
                    self._add_interface(vpp_interface,0))

        return wait_resource_task(self.node.vpp) > tasks

    #--------------------------------------------------------------------------
    # Internal methods
    #--------------------------------------------------------------------------

    def _add_interface(self, interface, br_domain):
        return BashTask(self.node, CMD_ADD_INTERFACE_TO_BR,
                {'interface': interface, 'br_domain': br_domain})

    def _del_interface(self,  interface, br_domain):
        raise NotImplementedError('Interface removal not supported')