2 # Copyright 2018 Cisco Systems, Inc. All rights reserved.
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 # not use this file except in compliance with the License. You may obtain
6 # a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations
17 # This module takes care of chaining routers
19 """NFVBENCH CHAIN DISCOVERY/STAGING.
21 This module takes care of staging/discovering resources that are participating in a
22 L3 benchmarking session: routers, networks, ports, routes.
23 If a resource is discovered with the same name, it will be reused.
24 Otherwise it will be created.
26 Once created/discovered, instances are checked to be in the active state (ready to pass traffic)
27 Configuration parameters that will influence how these resources are staged/related:
28 - openstack or no openstack
31 - number of VNF in each chain (PVP, PVVP)
32 - SRIOV and middle port SRIOV for port types
33 - whether networks are shared across chains or not
35 There is not traffic generation involved in this module.
39 from netaddr import IPAddress
40 from netaddr import IPNetwork
45 class ChainException(Exception):
46 """Exception while operating the chains."""
48 class ChainRouter(object):
49 """Could be a shared router across all chains or a chain private router."""
51 def __init__(self, manager, name, subnets, routes):
52 """Create a router for given chain."""
53 self.manager = manager
54 self.subnets = subnets
57 self.ports = [None, None]
63 LOG.error("Error creating router %s", self.name)
68 # Lookup if there is a matching router with same name
69 routers = self.manager.neutron_client.list_routers(name=self.name)
71 if routers['routers']:
72 router = routers['routers'][0]
73 # a router of same name already exists, we need to verify it has the same
76 for subnet in self.subnets:
77 if not self.get_router_interface(router['id'], subnet.network['subnets'][0]):
78 raise ChainException("Mismatch of 'subnet_id' for reused "
79 "router '{router}'.Router has no subnet id '{sub_id}'."
80 .format(router=self.name,
81 sub_id=subnet.network['subnets'][0]))
82 interfaces = self.manager.neutron_client.list_ports(device_id=router['id'])['ports']
83 # This string filters nfvbench networks in case when some other specific networks
84 # created and attached to the test nfvebnch router manually or automatically
85 # like in case of HA when neutron router virtually present on several network nodes
86 interfaces = [x for x in interfaces if x['fixed_ips'][0]['subnet_id'] in
87 [s.network['subnets'][0] for s in self.subnets]]
88 for interface in interfaces:
89 if self.is_ip_in_network(
90 interface['fixed_ips'][0]['ip_address'],
91 self.manager.config.traffic_generator.tg_gateway_ip_cidrs[0]) \
92 or self.is_ip_in_network(
93 interface['fixed_ips'][0]['ip_address'],
94 self.manager.config.traffic_generator.tg_gateway_ip_cidrs[1]):
95 self.ports[0] = interface
97 self.ports[1] = interface
99 for route in self.routes:
100 if route not in router['routes']:
101 LOG.info("Mismatch of 'router' for reused router '%s'."
102 "Router has no existing route destination '%s', "
103 "and nexthop '%s'.", self.name,
104 route['destination'],
106 LOG.info("New route added to router %s for reused ", self.name)
109 'routes': self.routes
112 self.manager.neutron_client.update_router(router['id'], body)
114 LOG.info('Reusing existing router: %s', self.name)
122 'admin_state_up': True
125 router = self.manager.neutron_client.create_router(body)['router']
126 router_id = router['id']
129 for subnet in self.subnets:
130 router_interface = {'subnet_id': subnet.network['subnets'][0]}
131 self.manager.neutron_client.add_interface_router(router_id, router_interface)
132 interfaces = self.manager.neutron_client.list_ports(device_id=router_id)['ports']
133 interfaces = [x for x in interfaces if x['fixed_ips'][0]['subnet_id'] in
134 [s.network['subnets'][0] for s in self.subnets]]
135 for interface in interfaces:
136 itf = interface['fixed_ips'][0]['ip_address']
137 cidr0 = self.manager.config.traffic_generator.tg_gateway_ip_cidrs[0]
138 cidr1 = self.manager.config.traffic_generator.tg_gateway_ip_cidrs[1]
139 if self.is_ip_in_network(itf, cidr0) or self.is_ip_in_network(itf, cidr1):
140 self.ports[0] = interface
142 self.ports[1] = interface
147 'routes': self.routes
150 self.manager.neutron_client.update_router(router_id, body)
152 LOG.info('Created router: %s.', self.name)
153 self.router = self.manager.neutron_client.show_router(router_id)
157 Extract UUID of this router.
159 :return: UUID of this router
161 return self.router['id']
163 def get_router_interface(self, router_id, subnet_id):
164 interfaces = self.manager.neutron_client.list_ports(device_id=router_id)['ports']
165 matching_interface = None
166 for interface in interfaces:
167 if interface['fixed_ips'][0]['subnet_id'] == subnet_id:
168 matching_interface = interface
169 return matching_interface
171 def is_ip_in_network(self, interface_ip, cidr):
172 return IPAddress(interface_ip) in IPNetwork(cidr)
175 """Delete this router."""
176 if not self.reuse and self.router:
178 while retry < self.manager.config.generic_retry_count:
180 self.manager.neutron_client.delete_router(self.router['id'])
181 LOG.info("Deleted router: %s", self.name)
185 LOG.info('Error deleting router %s (retry %d/%d)...',
188 self.manager.config.generic_retry_count)
189 time.sleep(self.manager.config.generic_poll_sec)
190 LOG.error('Unable to delete router: %s', self.name)