neutron/neutron/plugins/cisco/cfg_agent/device_drivers/csr1kv/csr1kv_routing_driver.py

687 lines
29 KiB
Python

# Copyright 2014 Cisco Systems, Inc. All rights reserved.
#
# 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.
import logging
import netaddr
import re
import time
import xml.etree.ElementTree as ET
import ciscoconfparse
from ncclient import manager
from oslo.config import cfg
from neutron.i18n import _LE, _LI, _LW
from neutron.plugins.cisco.cfg_agent import cfg_exceptions as cfg_exc
from neutron.plugins.cisco.cfg_agent.device_drivers.csr1kv import (
cisco_csr1kv_snippets as snippets)
from neutron.plugins.cisco.cfg_agent.device_drivers import devicedriver_api
LOG = logging.getLogger(__name__)
# N1kv constants
T1_PORT_NAME_PREFIX = 't1_p:' # T1 port/network is for VXLAN
T2_PORT_NAME_PREFIX = 't2_p:' # T2 port/network is for VLAN
class CSR1kvRoutingDriver(devicedriver_api.RoutingDriverBase):
"""CSR1kv Routing Driver.
This driver encapsulates the configuration logic via NETCONF protocol to
configure a CSR1kv Virtual Router (IOS-XE based) for implementing
Neutron L3 services. These services include routing, NAT and floating
IPs (as per Neutron terminology).
"""
DEV_NAME_LEN = 14
def __init__(self, **device_params):
try:
self._csr_host = device_params['management_ip_address']
self._csr_ssh_port = device_params['protocol_port']
credentials = device_params['credentials']
if credentials:
self._csr_user = credentials['username']
self._csr_password = credentials['password']
self._timeout = cfg.CONF.cfg_agent.device_connection_timeout
self._csr_conn = None
self._intfs_enabled = False
except KeyError as e:
LOG.error(_LE("Missing device parameter:%s. Aborting "
"CSR1kvRoutingDriver initialization"), e)
raise cfg_exc.CSR1kvInitializationException()
###### Public Functions ########
def router_added(self, ri):
self._csr_create_vrf(ri)
def router_removed(self, ri):
self._csr_remove_vrf(ri)
def internal_network_added(self, ri, port):
self._csr_create_subinterface(ri, port)
if port.get('ha_info') is not None and ri.ha_info['ha:enabled']:
self._csr_add_ha(ri, port)
def internal_network_removed(self, ri, port):
self._csr_remove_subinterface(port)
def external_gateway_added(self, ri, ex_gw_port):
self._csr_create_subinterface(ri, ex_gw_port)
ex_gw_ip = ex_gw_port['subnet']['gateway_ip']
if ex_gw_ip:
#Set default route via this network's gateway ip
self._csr_add_default_route(ri, ex_gw_ip)
def external_gateway_removed(self, ri, ex_gw_port):
ex_gw_ip = ex_gw_port['subnet']['gateway_ip']
if ex_gw_ip:
#Remove default route via this network's gateway ip
self._csr_remove_default_route(ri, ex_gw_ip)
#Finally, remove external network subinterface
self._csr_remove_subinterface(ex_gw_port)
def enable_internal_network_NAT(self, ri, port, ex_gw_port):
self._csr_add_internalnw_nat_rules(ri, port, ex_gw_port)
def disable_internal_network_NAT(self, ri, port, ex_gw_port):
self._csr_remove_internalnw_nat_rules(ri, [port], ex_gw_port)
def floating_ip_added(self, ri, ex_gw_port, floating_ip, fixed_ip):
self._csr_add_floating_ip(ri, floating_ip, fixed_ip)
def floating_ip_removed(self, ri, ex_gw_port, floating_ip, fixed_ip):
self._csr_remove_floating_ip(ri, ex_gw_port, floating_ip, fixed_ip)
def routes_updated(self, ri, action, route):
self._csr_update_routing_table(ri, action, route)
def clear_connection(self):
self._csr_conn = None
##### Internal Functions ####
def _csr_create_subinterface(self, ri, port):
vrf_name = self._csr_get_vrf_name(ri)
ip_cidr = port['ip_cidr']
netmask = netaddr.IPNetwork(ip_cidr).netmask
gateway_ip = ip_cidr.split('/')[0]
subinterface = self._get_interface_name_from_hosting_port(port)
vlan = self._get_interface_vlan_from_hosting_port(port)
self._create_subinterface(subinterface, vlan, vrf_name,
gateway_ip, netmask)
def _csr_remove_subinterface(self, port):
subinterface = self._get_interface_name_from_hosting_port(port)
self._remove_subinterface(subinterface)
def _csr_add_ha(self, ri, port):
func_dict = {
'HSRP': CSR1kvRoutingDriver._csr_add_ha_HSRP,
'VRRP': CSR1kvRoutingDriver._csr_add_ha_VRRP,
'GBLP': CSR1kvRoutingDriver._csr_add_ha_GBLP
}
#Invoke the right function for the ha type
func_dict[ri.ha_info['ha:type']](self, ri, port)
def _csr_add_ha_HSRP(self, ri, port):
priority = ri.ha_info['priority']
port_ha_info = port['ha_info']
group = port_ha_info['group']
ip = port_ha_info['virtual_port']['fixed_ips'][0]['ip_address']
if ip and group and priority:
vrf_name = self._csr_get_vrf_name(ri)
subinterface = self._get_interface_name_from_hosting_port(port)
self._set_ha_HSRP(subinterface, vrf_name, priority, group, ip)
def _csr_add_ha_VRRP(self, ri, port):
raise NotImplementedError()
def _csr_add_ha_GBLP(self, ri, port):
raise NotImplementedError()
def _csr_remove_ha(self, ri, port):
pass
def _csr_add_internalnw_nat_rules(self, ri, port, ex_port):
vrf_name = self._csr_get_vrf_name(ri)
in_vlan = self._get_interface_vlan_from_hosting_port(port)
acl_no = 'acl_' + str(in_vlan)
internal_cidr = port['ip_cidr']
internal_net = netaddr.IPNetwork(internal_cidr).network
netmask = netaddr.IPNetwork(internal_cidr).hostmask
inner_intfc = self._get_interface_name_from_hosting_port(port)
outer_intfc = self._get_interface_name_from_hosting_port(ex_port)
self._nat_rules_for_internet_access(acl_no, internal_net,
netmask, inner_intfc,
outer_intfc, vrf_name)
def _csr_remove_internalnw_nat_rules(self, ri, ports, ex_port):
acls = []
#First disable nat in all inner ports
for port in ports:
in_intfc_name = self._get_interface_name_from_hosting_port(port)
inner_vlan = self._get_interface_vlan_from_hosting_port(port)
acls.append("acl_" + str(inner_vlan))
self._remove_interface_nat(in_intfc_name, 'inside')
#Wait for two second
LOG.debug("Sleep for 2 seconds before clearing NAT rules")
time.sleep(2)
#Clear the NAT translation table
self._remove_dyn_nat_translations()
# Remove dynamic NAT rules and ACLs
vrf_name = self._csr_get_vrf_name(ri)
ext_intfc_name = self._get_interface_name_from_hosting_port(ex_port)
for acl in acls:
self._remove_dyn_nat_rule(acl, ext_intfc_name, vrf_name)
def _csr_add_default_route(self, ri, gw_ip):
vrf_name = self._csr_get_vrf_name(ri)
self._add_default_static_route(gw_ip, vrf_name)
def _csr_remove_default_route(self, ri, gw_ip):
vrf_name = self._csr_get_vrf_name(ri)
self._remove_default_static_route(gw_ip, vrf_name)
def _csr_add_floating_ip(self, ri, floating_ip, fixed_ip):
vrf_name = self._csr_get_vrf_name(ri)
self._add_floating_ip(floating_ip, fixed_ip, vrf_name)
def _csr_remove_floating_ip(self, ri, ex_gw_port, floating_ip, fixed_ip):
vrf_name = self._csr_get_vrf_name(ri)
out_intfc_name = self._get_interface_name_from_hosting_port(ex_gw_port)
# First remove NAT from outer interface
self._remove_interface_nat(out_intfc_name, 'outside')
#Clear the NAT translation table
self._remove_dyn_nat_translations()
#Remove the floating ip
self._remove_floating_ip(floating_ip, fixed_ip, vrf_name)
#Enable NAT on outer interface
self._add_interface_nat(out_intfc_name, 'outside')
def _csr_update_routing_table(self, ri, action, route):
vrf_name = self._csr_get_vrf_name(ri)
destination_net = netaddr.IPNetwork(route['destination'])
dest = destination_net.network
dest_mask = destination_net.netmask
next_hop = route['nexthop']
if action is 'replace':
self._add_static_route(dest, dest_mask, next_hop, vrf_name)
elif action is 'delete':
self._remove_static_route(dest, dest_mask, next_hop, vrf_name)
else:
LOG.error(_LE('Unknown route command %s'), action)
def _csr_create_vrf(self, ri):
vrf_name = self._csr_get_vrf_name(ri)
self._create_vrf(vrf_name)
def _csr_remove_vrf(self, ri):
vrf_name = self._csr_get_vrf_name(ri)
self._remove_vrf(vrf_name)
def _csr_get_vrf_name(self, ri):
return ri.router_name()[:self.DEV_NAME_LEN]
def _get_connection(self):
"""Make SSH connection to the CSR.
The external ncclient library is used for creating this connection.
This method keeps state of any existing connections and reuses them if
already connected. Also CSR1kv's interfaces (except management) are
disabled by default when it is booted. So if connecting for the first
time, driver will enable all other interfaces and keep that status in
the `_intfs_enabled` flag.
"""
try:
if self._csr_conn and self._csr_conn.connected:
return self._csr_conn
else:
self._csr_conn = manager.connect(host=self._csr_host,
port=self._csr_ssh_port,
username=self._csr_user,
password=self._csr_password,
device_params={'name': "csr"},
timeout=self._timeout)
if not self._intfs_enabled:
self._intfs_enabled = self._enable_intfs(self._csr_conn)
return self._csr_conn
except Exception as e:
conn_params = {'host': self._csr_host, 'port': self._csr_ssh_port,
'user': self._csr_user,
'timeout': self._timeout, 'reason': e.message}
raise cfg_exc.CSR1kvConnectionException(**conn_params)
def _get_interface_name_from_hosting_port(self, port):
vlan = self._get_interface_vlan_from_hosting_port(port)
int_no = self._get_interface_no_from_hosting_port(port)
intfc_name = 'GigabitEthernet%s.%s' % (int_no, vlan)
return intfc_name
@staticmethod
def _get_interface_vlan_from_hosting_port(port):
return port['hosting_info']['segmentation_id']
@staticmethod
def _get_interface_no_from_hosting_port(port):
"""Calculate interface number from the hosting port's name.
Interfaces in the CSR1kv are created in pairs (T1 and T2) where
T1 interface is used for VLAN and T2 interface for VXLAN traffic
respectively. On the neutron side these are named T1 and T2 ports and
follows the naming convention: <Tx_PORT_NAME_PREFIX>:<PAIR_INDEX>
where the `PORT_NAME_PREFIX` indicates either VLAN or VXLAN and
`PAIR_INDEX` is the pair number. `PAIR_INDEX` starts at 1.
In CSR1kv, GigabitEthernet 0 is not present and GigabitEthernet 1
is used as a management interface (Note: this might change in
future). So the first (T1,T2) pair corresponds to
(GigabitEthernet 2, GigabitEthernet 3) and so forth. This function
extracts the `PAIR_INDEX` and calculates the corresponding interface
number.
:param port: neutron port corresponding to the interface.
:return: number of the interface (eg: 1 in case of GigabitEthernet1)
"""
_name = port['hosting_info']['hosting_port_name']
if_type = _name.split(':')[0] + ':'
if if_type == T1_PORT_NAME_PREFIX:
return str(int(_name.split(':')[1]) * 2)
elif if_type == T2_PORT_NAME_PREFIX:
return str(int(_name.split(':')[1]) * 2 + 1)
else:
params = {'attribute': 'hosting_port_name', 'value': _name}
raise cfg_exc.CSR1kvUnknownValueException(**params)
def _get_interfaces(self):
"""Get a list of interfaces on this hosting device.
:return: List of the interfaces
"""
ioscfg = self._get_running_config()
parse = ciscoconfparse.CiscoConfParse(ioscfg)
intfs_raw = parse.find_lines("^interface GigabitEthernet")
intfs = [raw_if.strip().split(' ')[1] for raw_if in intfs_raw]
LOG.info(_LI("Interfaces:%s"), intfs)
return intfs
def _get_interface_ip(self, interface_name):
"""Get the ip address for an interface.
:param interface_name: interface_name as a string
:return: ip address of interface as a string
"""
ioscfg = self._get_running_config()
parse = ciscoconfparse.CiscoConfParse(ioscfg)
children = parse.find_children("^interface %s" % interface_name)
for line in children:
if 'ip address' in line:
ip_address = line.strip().split(' ')[2]
LOG.info(_LI("IP Address:%s"), ip_address)
return ip_address
LOG.warning(_LW("Cannot find interface: %s"), interface_name)
return None
def _interface_exists(self, interface):
"""Check whether interface exists."""
ioscfg = self._get_running_config()
parse = ciscoconfparse.CiscoConfParse(ioscfg)
intfs_raw = parse.find_lines("^interface " + interface)
return len(intfs_raw) > 0
def _enable_intfs(self, conn):
"""Enable the interfaces of a CSR1kv Virtual Router.
When the virtual router first boots up, all interfaces except
management are down. This method will enable all data interfaces.
Note: In CSR1kv, GigabitEthernet 0 is not present. GigabitEthernet 1
is used as management and GigabitEthernet 2 and up are used for data.
This might change in future releases.
Currently only the second and third Gig interfaces corresponding to a
single (T1,T2) pair and configured as trunk for VLAN and VXLAN
is enabled.
:param conn: Connection object
:return: True or False
"""
#ToDo(Hareesh): Interfaces are hard coded for now. Make it dynamic.
interfaces = ['GigabitEthernet 2', 'GigabitEthernet 3']
try:
for i in interfaces:
confstr = snippets.ENABLE_INTF % i
rpc_obj = conn.edit_config(target='running', config=confstr)
if self._check_response(rpc_obj, 'ENABLE_INTF'):
LOG.info(_LI("Enabled interface %s "), i)
time.sleep(1)
except Exception:
return False
return True
def _get_vrfs(self):
"""Get the current VRFs configured in the device.
:return: A list of vrf names as string
"""
vrfs = []
ioscfg = self._get_running_config()
parse = ciscoconfparse.CiscoConfParse(ioscfg)
vrfs_raw = parse.find_lines("^ip vrf")
for line in vrfs_raw:
# raw format ['ip vrf <vrf-name>',....]
vrf_name = line.strip().split(' ')[2]
vrfs.append(vrf_name)
LOG.info(_LI("VRFs:%s"), vrfs)
return vrfs
def _get_capabilities(self):
"""Get the servers NETCONF capabilities.
:return: List of server capabilities.
"""
conn = self._get_connection()
capabilities = []
for c in conn.server_capabilities:
capabilities.append(c)
LOG.debug("Server capabilities: %s", capabilities)
return capabilities
def _get_running_config(self):
"""Get the CSR's current running config.
:return: Current IOS running config as multiline string
"""
conn = self._get_connection()
config = conn.get_config(source="running")
if config:
root = ET.fromstring(config._raw)
running_config = root[0][0]
rgx = re.compile("\r*\n+")
ioscfg = rgx.split(running_config.text)
return ioscfg
def _check_acl(self, acl_no, network, netmask):
"""Check a ACL config exists in the running config.
:param acl_no: access control list (ACL) number
:param network: network which this ACL permits
:param netmask: netmask of the network
:return:
"""
exp_cfg_lines = ['ip access-list standard ' + str(acl_no),
' permit ' + str(network) + ' ' + str(netmask)]
ioscfg = self._get_running_config()
parse = ciscoconfparse.CiscoConfParse(ioscfg)
acls_raw = parse.find_children(exp_cfg_lines[0])
if acls_raw:
if exp_cfg_lines[1] in acls_raw:
return True
LOG.error(_LE("Mismatch in ACL configuration for %s"), acl_no)
return False
LOG.debug("%s is not present in config", acl_no)
return False
def _cfg_exists(self, cfg_str):
"""Check a partial config string exists in the running config.
:param cfg_str: config string to check
:return : True or False
"""
ioscfg = self._get_running_config()
parse = ciscoconfparse.CiscoConfParse(ioscfg)
cfg_raw = parse.find_lines("^" + cfg_str)
LOG.debug("_cfg_exists(): Found lines %s", cfg_raw)
return len(cfg_raw) > 0
def _set_interface(self, name, ip_address, mask):
conn = self._get_connection()
confstr = snippets.SET_INTC % (name, ip_address, mask)
rpc_obj = conn.edit_config(target='running', config=confstr)
self._check_response(rpc_obj, 'SET_INTC')
def _create_vrf(self, vrf_name):
try:
conn = self._get_connection()
confstr = snippets.CREATE_VRF % vrf_name
rpc_obj = conn.edit_config(target='running', config=confstr)
if self._check_response(rpc_obj, 'CREATE_VRF'):
LOG.info(_LI("VRF %s successfully created"), vrf_name)
except Exception:
LOG.exception(_LE("Failed creating VRF %s"), vrf_name)
def _remove_vrf(self, vrf_name):
if vrf_name in self._get_vrfs():
conn = self._get_connection()
confstr = snippets.REMOVE_VRF % vrf_name
rpc_obj = conn.edit_config(target='running', config=confstr)
if self._check_response(rpc_obj, 'REMOVE_VRF'):
LOG.info(_LI("VRF %s removed"), vrf_name)
else:
LOG.warning(_LW("VRF %s not present"), vrf_name)
def _create_subinterface(self, subinterface, vlan_id, vrf_name, ip, mask):
if vrf_name not in self._get_vrfs():
LOG.error(_LE("VRF %s not present"), vrf_name)
confstr = snippets.CREATE_SUBINTERFACE % (subinterface, vlan_id,
vrf_name, ip, mask)
self._edit_running_config(confstr, 'CREATE_SUBINTERFACE')
def _remove_subinterface(self, subinterface):
#Optional : verify this is the correct subinterface
if self._interface_exists(subinterface):
confstr = snippets.REMOVE_SUBINTERFACE % subinterface
self._edit_running_config(confstr, 'REMOVE_SUBINTERFACE')
def _set_ha_HSRP(self, subinterface, vrf_name, priority, group, ip):
if vrf_name not in self._get_vrfs():
LOG.error(_LE("VRF %s not present"), vrf_name)
confstr = snippets.SET_INTC_HSRP % (subinterface, vrf_name, group,
priority, group, ip)
action = "SET_INTC_HSRP (Group: %s, Priority: % s)" % (group, priority)
self._edit_running_config(confstr, action)
def _remove_ha_HSRP(self, subinterface, group):
confstr = snippets.REMOVE_INTC_HSRP % (subinterface, group)
action = ("REMOVE_INTC_HSRP (subinterface:%s, Group:%s)"
% (subinterface, group))
self._edit_running_config(confstr, action)
def _get_interface_cfg(self, interface):
ioscfg = self._get_running_config()
parse = ciscoconfparse.CiscoConfParse(ioscfg)
return parse.find_children('interface ' + interface)
def _nat_rules_for_internet_access(self, acl_no, network,
netmask,
inner_intfc,
outer_intfc,
vrf_name):
"""Configure the NAT rules for an internal network.
Configuring NAT rules in the CSR1kv is a three step process. First
create an ACL for the IP range of the internal network. Then enable
dynamic source NATing on the external interface of the CSR for this
ACL and VRF of the neutron router. Finally enable NAT on the
interfaces of the CSR where the internal and external networks are
connected.
:param acl_no: ACL number of the internal network.
:param network: internal network
:param netmask: netmask of the internal network.
:param inner_intfc: (name of) interface connected to the internal
network
:param outer_intfc: (name of) interface connected to the external
network
:param vrf_name: VRF corresponding to this virtual router
:return: True if configuration succeeded
:raises: neutron.plugins.cisco.cfg_agent.cfg_exceptions.
CSR1kvConfigException
"""
conn = self._get_connection()
# Duplicate ACL creation throws error, so checking
# it first. Remove it in future as this is not common in production
acl_present = self._check_acl(acl_no, network, netmask)
if not acl_present:
confstr = snippets.CREATE_ACL % (acl_no, network, netmask)
rpc_obj = conn.edit_config(target='running', config=confstr)
self._check_response(rpc_obj, 'CREATE_ACL')
confstr = snippets.SET_DYN_SRC_TRL_INTFC % (acl_no, outer_intfc,
vrf_name)
rpc_obj = conn.edit_config(target='running', config=confstr)
self._check_response(rpc_obj, 'CREATE_SNAT')
confstr = snippets.SET_NAT % (inner_intfc, 'inside')
rpc_obj = conn.edit_config(target='running', config=confstr)
self._check_response(rpc_obj, 'SET_NAT')
confstr = snippets.SET_NAT % (outer_intfc, 'outside')
rpc_obj = conn.edit_config(target='running', config=confstr)
self._check_response(rpc_obj, 'SET_NAT')
def _add_interface_nat(self, intfc_name, intfc_type):
conn = self._get_connection()
confstr = snippets.SET_NAT % (intfc_name, intfc_type)
rpc_obj = conn.edit_config(target='running', config=confstr)
self._check_response(rpc_obj, 'SET_NAT ' + intfc_type)
def _remove_interface_nat(self, intfc_name, intfc_type):
conn = self._get_connection()
confstr = snippets.REMOVE_NAT % (intfc_name, intfc_type)
rpc_obj = conn.edit_config(target='running', config=confstr)
self._check_response(rpc_obj, 'REMOVE_NAT ' + intfc_type)
def _remove_dyn_nat_rule(self, acl_no, outer_intfc_name, vrf_name):
conn = self._get_connection()
confstr = snippets.SNAT_CFG % (acl_no, outer_intfc_name, vrf_name)
if self._cfg_exists(confstr):
confstr = snippets.REMOVE_DYN_SRC_TRL_INTFC % (acl_no,
outer_intfc_name,
vrf_name)
rpc_obj = conn.edit_config(target='running', config=confstr)
self._check_response(rpc_obj, 'REMOVE_DYN_SRC_TRL_INTFC')
confstr = snippets.REMOVE_ACL % acl_no
rpc_obj = conn.edit_config(target='running', config=confstr)
self._check_response(rpc_obj, 'REMOVE_ACL')
def _remove_dyn_nat_translations(self):
conn = self._get_connection()
confstr = snippets.CLEAR_DYN_NAT_TRANS
rpc_obj = conn.edit_config(target='running', config=confstr)
self._check_response(rpc_obj, 'CLEAR_DYN_NAT_TRANS')
def _add_floating_ip(self, floating_ip, fixed_ip, vrf):
conn = self._get_connection()
confstr = snippets.SET_STATIC_SRC_TRL % (fixed_ip, floating_ip, vrf)
rpc_obj = conn.edit_config(target='running', config=confstr)
self._check_response(rpc_obj, 'SET_STATIC_SRC_TRL')
def _remove_floating_ip(self, floating_ip, fixed_ip, vrf):
conn = self._get_connection()
confstr = snippets.REMOVE_STATIC_SRC_TRL % (fixed_ip, floating_ip, vrf)
rpc_obj = conn.edit_config(target='running', config=confstr)
self._check_response(rpc_obj, 'REMOVE_STATIC_SRC_TRL')
def _get_floating_ip_cfg(self):
ioscfg = self._get_running_config()
parse = ciscoconfparse.CiscoConfParse(ioscfg)
res = parse.find_lines('ip nat inside source static')
return res
def _add_static_route(self, dest, dest_mask, next_hop, vrf):
conn = self._get_connection()
confstr = snippets.SET_IP_ROUTE % (vrf, dest, dest_mask, next_hop)
rpc_obj = conn.edit_config(target='running', config=confstr)
self._check_response(rpc_obj, 'SET_IP_ROUTE')
def _remove_static_route(self, dest, dest_mask, next_hop, vrf):
conn = self._get_connection()
confstr = snippets.REMOVE_IP_ROUTE % (vrf, dest, dest_mask, next_hop)
rpc_obj = conn.edit_config(target='running', config=confstr)
self._check_response(rpc_obj, 'REMOVE_IP_ROUTE')
def _get_static_route_cfg(self):
ioscfg = self._get_running_config()
parse = ciscoconfparse.CiscoConfParse(ioscfg)
return parse.find_lines('ip route')
def _add_default_static_route(self, gw_ip, vrf):
conn = self._get_connection()
confstr = snippets.DEFAULT_ROUTE_CFG % (vrf, gw_ip)
if not self._cfg_exists(confstr):
confstr = snippets.SET_DEFAULT_ROUTE % (vrf, gw_ip)
rpc_obj = conn.edit_config(target='running', config=confstr)
self._check_response(rpc_obj, 'SET_DEFAULT_ROUTE')
def _remove_default_static_route(self, gw_ip, vrf):
conn = self._get_connection()
confstr = snippets.DEFAULT_ROUTE_CFG % (vrf, gw_ip)
if self._cfg_exists(confstr):
confstr = snippets.REMOVE_DEFAULT_ROUTE % (vrf, gw_ip)
rpc_obj = conn.edit_config(target='running', config=confstr)
self._check_response(rpc_obj, 'REMOVE_DEFAULT_ROUTE')
def _edit_running_config(self, confstr, snippet):
conn = self._get_connection()
rpc_obj = conn.edit_config(target='running', config=confstr)
self._check_response(rpc_obj, snippet)
@staticmethod
def _check_response(rpc_obj, snippet_name):
"""This function checks the rpc response object for status.
This function takes as input the response rpc_obj and the snippet name
that was executed. It parses it to see, if the last edit operation was
a success or not.
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply message-id="urn:uuid:81bf8082-....-b69a-000c29e1b85c"
xmlns="urn:ietf:params:netconf:base:1.0">
<ok />
</rpc-reply>
In case of error, CSR1kv sends a response as follows.
We take the error type and tag.
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply message-id="urn:uuid:81bf8082-....-b69a-000c29e1b85c"
xmlns="urn:ietf:params:netconf:base:1.0">
<rpc-error>
<error-type>protocol</error-type>
<error-tag>operation-failed</error-tag>
<error-severity>error</error-severity>
</rpc-error>
</rpc-reply>
:return: True if the config operation completed successfully
:raises: neutron.plugins.cisco.cfg_agent.cfg_exceptions.
CSR1kvConfigException
"""
LOG.debug("RPCReply for %(snippet_name)s is %(rpc_obj)s",
{'snippet_name': snippet_name, 'rpc_obj': rpc_obj.xml})
xml_str = rpc_obj.xml
if "<ok />" in xml_str:
LOG.debug("RPCReply for %s is OK", snippet_name)
LOG.info(_LI("%s successfully executed"), snippet_name)
return True
# Not Ok, we throw a ConfigurationException
e_type = rpc_obj._root[0][0].text
e_tag = rpc_obj._root[0][1].text
params = {'snippet': snippet_name, 'type': e_type, 'tag': e_tag}
raise cfg_exc.CSR1kvConfigException(**params)