CPlatform.py revision f91190c7
1#!/router/bin/python
2
3from interfaces_e import IFType
4from platform_cmd_link import *
5import CustomLogger
6import misc_methods
7import re
8import time
9import CProgressDisp
10from CShowParser import CShowParser
11
12class CPlatform(object):
13    def __init__(self, silent_mode):
14        self.if_mngr            = CIfManager()
15        self.cmd_link           = CCommandLink(silent_mode)
16        self.nat_config         = None
17        self.stat_route_config  = None
18        self.running_image      = None
19        self.needed_image_path  = None
20        self.tftp_cfg           = None
21        self.config_history     = { 'basic_if_config' : False, 'tftp_server_config' : False }
22
23    def configure_basic_interfaces(self, mtu = 4000):
24
25        cache = CCommandCache()
26        for dual_if in self.if_mngr.get_dual_if_list():
27            client_if_command_set   = []
28            server_if_command_set   = []
29
30            client_if_command_set.append ('mac-address {mac}'.format( mac = dual_if.client_if.get_src_mac_addr()) )
31            client_if_command_set.append ('mtu %s' % mtu)
32            client_if_command_set.append ('ip address {ip} 255.255.255.0'.format( ip = dual_if.client_if.get_ipv4_addr() ))
33            client_if_command_set.append ('ipv6 address {ip}/64'.format( ip = dual_if.client_if.get_ipv6_addr() ))
34
35            cache.add('IF', client_if_command_set, dual_if.client_if.get_name())
36
37            server_if_command_set.append ('mac-address {mac}'.format( mac = dual_if.server_if.get_src_mac_addr()) )
38            server_if_command_set.append ('mtu %s' % mtu)
39            server_if_command_set.append ('ip address {ip} 255.255.255.0'.format( ip = dual_if.server_if.get_ipv4_addr() ))
40            server_if_command_set.append ('ipv6 address {ip}/64'.format( ip = dual_if.server_if.get_ipv6_addr() ))
41
42            cache.add('IF', server_if_command_set, dual_if.server_if.get_name())
43
44        self.cmd_link.run_single_command(cache)
45        self.config_history['basic_if_config'] = True
46
47
48
49    def configure_basic_filtered_interfaces(self, intf_list, mtu = 4000):
50
51        cache = CCommandCache()
52        for intf in intf_list:
53            if_command_set   = []
54
55            if_command_set.append ('mac-address {mac}'.format( mac = intf.get_src_mac_addr()) )
56            if_command_set.append ('mtu %s' % mtu)
57            if_command_set.append ('ip address {ip} 255.255.255.0'.format( ip = intf.get_ipv4_addr() ))
58            if_command_set.append ('ipv6 address {ip}/64'.format( ip = intf.get_ipv6_addr() ))
59
60            cache.add('IF', if_command_set, intf.get_name())
61
62        self.cmd_link.run_single_command(cache)
63
64
65    def load_clean_config (self, config_filename = "clean_config.cfg", cfg_drive = "bootflash"):
66        self.clear_nat_translations()
67
68        cache = CCommandCache()
69        cache.add('EXEC', "configure replace {drive}:{file} force".format(drive = cfg_drive, file = config_filename))
70        res = self.cmd_link.run_single_command(cache)
71        if 'Rollback Done' not in res:
72            raise UserWarning('Could not load clean config, please verify file exists. Response:\n%s' % res)
73
74    def config_pbr (self, mode = 'config'):
75        idx = 1
76        unconfig_str = '' if mode=='config' else 'no '
77
78        cache = CCommandCache()
79        pre_commit_cache = CCommandCache()
80        pre_commit_set = set([])
81
82        for dual_if in self.if_mngr.get_dual_if_list():
83            client_if_command_set   = []
84            server_if_command_set   = []
85            conf_t_command_set      = []
86            client_net_next_hop = misc_methods.get_single_net_client_addr(dual_if.server_if.get_ipv4_addr() )
87            server_net_next_hop = misc_methods.get_single_net_client_addr(dual_if.client_if.get_ipv4_addr() )
88
89            if dual_if.is_duplicated():
90                # define the relevant VRF name
91                pre_commit_set.add('{mode}ip vrf {dup}'.format( mode = unconfig_str, dup = dual_if.get_vrf_name()) )
92
93                # assign VRF to interfaces, config interfaces with relevant route-map
94                client_if_command_set.append ('{mode}ip vrf forwarding {dup}'.format( mode = unconfig_str, dup = dual_if.get_vrf_name()) )
95                client_if_command_set.append ('{mode}ip policy route-map {dup}_{p1}_to_{p2}'.format(
96                    mode = unconfig_str,
97                    dup = dual_if.get_vrf_name(),
98                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
99                server_if_command_set.append ('{mode}ip vrf forwarding {dup}'.format( mode = unconfig_str, dup = dual_if.get_vrf_name()) )
100                server_if_command_set.append ('{mode}ip policy route-map {dup}_{p2}_to_{p1}'.format(
101                    mode = unconfig_str,
102                    dup = dual_if.get_vrf_name(),
103                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
104
105                # config route-map routing
106                conf_t_command_set.append('{mode}route-map {dup}_{p1}_to_{p2} permit 10'.format(
107                    mode = unconfig_str,
108                    dup = dual_if.get_vrf_name(),
109                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
110                if mode == 'config':
111                    conf_t_command_set.append('set ip next-hop {next_hop}'.format(
112                         next_hop = client_net_next_hop) )
113                conf_t_command_set.append('{mode}route-map {dup}_{p2}_to_{p1} permit 10'.format(
114                    mode = unconfig_str,
115                    dup = dual_if.get_vrf_name(),
116                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
117                if mode == 'config':
118                    conf_t_command_set.append('set ip next-hop {next_hop}'.format(
119                         next_hop = server_net_next_hop) )
120
121                # config global arp to interfaces net address and vrf
122                conf_t_command_set.append('{mode}arp vrf {dup} {next_hop} {dest_mac} arpa'.format(
123                    mode = unconfig_str,
124                    dup = dual_if.get_vrf_name(),
125                    next_hop = server_net_next_hop,
126                    dest_mac = dual_if.client_if.get_dest_mac()))
127                conf_t_command_set.append('{mode}arp vrf {dup} {next_hop} {dest_mac} arpa'.format(
128                    mode = unconfig_str,
129                    dup = dual_if.get_vrf_name(),
130                    next_hop = client_net_next_hop,
131                    dest_mac = dual_if.server_if.get_dest_mac()))
132            else:
133                # config interfaces with relevant route-map
134                client_if_command_set.append ('{mode}ip policy route-map {p1}_to_{p2}'.format(
135                    mode = unconfig_str,
136                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
137                server_if_command_set.append ('{mode}ip policy route-map {p2}_to_{p1}'.format(
138                    mode = unconfig_str,
139                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
140
141                # config route-map routing
142                conf_t_command_set.append('{mode}route-map {p1}_to_{p2} permit 10'.format(
143                    mode = unconfig_str,
144                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
145                if mode == 'config':
146                    conf_t_command_set.append('set ip next-hop {next_hop}'.format(
147                         next_hop = client_net_next_hop) )
148                conf_t_command_set.append('{mode}route-map {p2}_to_{p1} permit 10'.format(
149                    mode = unconfig_str,
150                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
151                if mode == 'config':
152                    conf_t_command_set.append('set ip next-hop {next_hop}'.format(
153                         next_hop = server_net_next_hop) )
154
155                # config global arp to interfaces net address
156                conf_t_command_set.append('{mode}arp {next_hop} {dest_mac} arpa'.format(
157                    mode = unconfig_str,
158                    next_hop = server_net_next_hop,
159                    dest_mac = dual_if.client_if.get_dest_mac()))
160                conf_t_command_set.append('{mode}arp {next_hop} {dest_mac} arpa'.format(
161                    mode = unconfig_str,
162                    next_hop = client_net_next_hop,
163                    dest_mac = dual_if.server_if.get_dest_mac()))
164
165            # assign generated config list to cache
166            cache.add('IF', server_if_command_set, dual_if.server_if.get_name())
167            cache.add('IF', client_if_command_set, dual_if.client_if.get_name())
168            cache.add('CONF', conf_t_command_set)
169            idx += 2
170
171        # finish handling pre-config cache
172        pre_commit_set = list(pre_commit_set)
173#       pre_commit_set.append('exit')
174        pre_commit_cache.add('CONF', pre_commit_set )
175        # deploy the configs (order is important!)
176        self.cmd_link.run_command( [pre_commit_cache, cache] )
177        if self.config_history['basic_if_config']:
178            # in this case, duplicated interfaces will lose its ip address.
179            # re-config IPv4 addresses
180            self.configure_basic_filtered_interfaces(self.if_mngr.get_duplicated_if() )
181
182    def config_no_pbr (self):
183        self.config_pbr(mode = 'unconfig')
184
185    def config_static_routing (self, stat_route_obj, mode = 'config'):
186
187        if mode == 'config':
188            self.stat_route_config = stat_route_obj   # save the latest static route config for future removal purposes
189
190        unconfig_str = '' if mode=='config' else 'no '
191        cache              = CCommandCache()
192        pre_commit_cache   = CCommandCache()
193        pre_commit_set     = set([])
194        current_dup_intf   = None
195        # client_net       = None
196        # server_net       = None
197        client_net         = stat_route_obj.client_net_start
198        server_net         = stat_route_obj.server_net_start
199        conf_t_command_set = []
200
201        for dual_if in self.if_mngr.get_dual_if_list():
202
203            # handle duplicated addressing generation
204            if dual_if.is_duplicated():
205                if dual_if.get_vrf_name() != current_dup_intf:
206                    # if this is a dual interfaces, and it is different from the one we proccessed so far, reset static route addressing
207                    current_dup_intf = dual_if.get_vrf_name()
208                    client_net       = stat_route_obj.client_net_start
209                    server_net       = stat_route_obj.server_net_start
210            else:
211                if current_dup_intf is not None:
212                    current_dup_intf = None
213                    client_net       = stat_route_obj.client_net_start
214                    server_net       = stat_route_obj.server_net_start
215
216            client_net_next_hop = misc_methods.get_single_net_client_addr(dual_if.server_if.get_ipv4_addr() )
217            server_net_next_hop = misc_methods.get_single_net_client_addr(dual_if.client_if.get_ipv4_addr() )
218
219            # handle static route configuration for the interfaces
220            if dual_if.is_duplicated():
221                client_if_command_set   = []
222                server_if_command_set   = []
223
224                # define the relevant VRF name
225                pre_commit_set.add('{mode}ip vrf {dup}'.format( mode = unconfig_str, dup = dual_if.get_vrf_name()) )
226
227                # assign VRF to interfaces, config interfaces with relevant route-map
228                client_if_command_set.append ('{mode}ip vrf forwarding {dup}'.format( mode = unconfig_str, dup = dual_if.get_vrf_name()) )
229                server_if_command_set.append ('{mode}ip vrf forwarding {dup}'.format( mode = unconfig_str, dup = dual_if.get_vrf_name()) )
230
231                conf_t_command_set.append( "{mode}ip route vrf {dup} {next_net} {dest_mask} {next_hop}".format(
232                    mode = unconfig_str,
233                    dup = dual_if.get_vrf_name(),
234                    next_net = client_net,
235                    dest_mask = stat_route_obj.client_mask,
236                    next_hop = client_net_next_hop))
237                conf_t_command_set.append( "{mode}ip route vrf {dup} {next_net} {dest_mask} {next_hop}".format(
238                    mode = unconfig_str,
239                    dup = dual_if.get_vrf_name(),
240                    next_net = server_net,
241                    dest_mask = stat_route_obj.server_mask,
242                    next_hop = server_net_next_hop))
243
244                # config global arp to interfaces net address and vrf
245                conf_t_command_set.append('{mode}arp vrf {dup} {next_hop} {dest_mac} arpa'.format(
246                    mode = unconfig_str,
247                    dup = dual_if.get_vrf_name(),
248                    next_hop = server_net_next_hop,
249                    dest_mac = dual_if.client_if.get_dest_mac()))
250                conf_t_command_set.append('{mode}arp vrf {dup} {next_hop} {dest_mac} arpa'.format(
251                    mode = unconfig_str,
252                    dup = dual_if.get_vrf_name(),
253                    next_hop = client_net_next_hop,
254                    dest_mac = dual_if.server_if.get_dest_mac()))
255
256                # assign generated interfaces config list to cache
257                cache.add('IF', server_if_command_set, dual_if.server_if.get_name())
258                cache.add('IF', client_if_command_set, dual_if.client_if.get_name())
259
260            else:
261                conf_t_command_set.append( "{mode}ip route {next_net} {dest_mask} {next_hop}".format(
262                    mode = unconfig_str,
263                    next_net = client_net,
264                    dest_mask = stat_route_obj.client_mask,
265                    next_hop = server_net_next_hop))
266                conf_t_command_set.append( "{mode}ip route {next_net} {dest_mask} {next_hop}".format(
267                    mode = unconfig_str,
268                    next_net = server_net,
269                    dest_mask = stat_route_obj.server_mask,
270                    next_hop = client_net_next_hop))
271
272                # config global arp to interfaces net address
273                conf_t_command_set.append('{mode}arp {next_hop} {dest_mac} arpa'.format(
274                    mode = unconfig_str,
275                    next_hop = server_net_next_hop,
276                    dest_mac = dual_if.client_if.get_dest_mac()))
277                conf_t_command_set.append('{mode}arp {next_hop} {dest_mac} arpa'.format(
278                    mode = unconfig_str,
279                    next_hop = client_net_next_hop,
280                    dest_mac = dual_if.server_if.get_dest_mac()))
281
282            # bump up to the next client network address
283            client_net = misc_methods.get_single_net_client_addr(client_net, stat_route_obj.net_increment)
284            server_net = misc_methods.get_single_net_client_addr(server_net, stat_route_obj.net_increment)
285
286
287        # finish handling pre-config cache
288        pre_commit_set = list(pre_commit_set)
289#       pre_commit_set.append('exit')
290        pre_commit_cache.add('CONF', pre_commit_set )
291        # assign generated config list to cache
292        cache.add('CONF', conf_t_command_set)
293        # deploy the configs (order is important!)
294        self.cmd_link.run_command( [pre_commit_cache, cache] )
295        if self.config_history['basic_if_config']:
296            # in this case, duplicated interfaces will lose its ip address.
297            # re-config IPv4 addresses
298            self.configure_basic_filtered_interfaces(self.if_mngr.get_duplicated_if() )
299
300
301    def config_no_static_routing (self, stat_route_obj = None):
302
303        if stat_route_obj is None and self.stat_route_config is not None:
304            self.config_static_routing(self.stat_route_config, mode = 'unconfig')
305            self.stat_route_config = None  # reverse current static route config back to None (no nat config is known to run).
306        elif stat_route_obj is not None:
307            self.config_static_routing(stat_route_obj, mode = 'unconfig')
308        else:
309            raise UserWarning('No static route configuration is available for removal.')
310
311    def config_nbar_pd (self, mode = 'config'):
312        unconfig_str = '' if mode=='config' else 'no '
313        cache = CCommandCache()
314
315        for intf in self.if_mngr.get_if_list(if_type = IFType.Client):
316            cache.add('IF', "{mode}ip nbar protocol-discovery".format( mode = unconfig_str ), intf.get_name())
317
318        self.cmd_link.run_single_command( cache )
319
320    def config_no_nbar_pd (self):
321        self.config_nbar_pd (mode = 'unconfig')
322
323
324    def config_nat_verify (self, mode = 'config'):
325
326        # toggle all duplicate interfaces
327        # dup_ifs = self.if_mngr.get_duplicated_if()
328        if mode=='config':
329            self.toggle_duplicated_intf(action = 'down')
330            # self.__toggle_interfaces(dup_ifs, action = 'down' )
331        else:
332            # if we're in 'unconfig', toggle duplicated interfaces back up
333            self.toggle_duplicated_intf(action = 'up')
334            # self.__toggle_interfaces(dup_ifs)
335
336    def config_no_nat_verify (self):
337        self.config_nat_verify(mode = 'unconfig')
338
339    def config_nat (self, nat_obj, mode = 'config'):
340
341        if mode == 'config':
342            self.nat_config = nat_obj   # save the latest nat config for future removal purposes
343
344        cache               = CCommandCache()
345        conf_t_command_set  = []
346        client_net          = nat_obj.clients_net_start
347        pool_net            = nat_obj.nat_pool_start
348        unconfig_str        = '' if mode=='config' else 'no '
349
350        # toggle all duplicate interfaces
351        # dup_ifs = self.if_mngr.get_duplicated_if()
352        if mode=='config':
353            self.toggle_duplicated_intf(action = 'down')
354            # self.__toggle_interfaces(dup_ifs, action = 'down' )
355        else:
356            # if we're in 'unconfig', toggle duplicated interfaces back up
357            self.toggle_duplicated_intf(action = 'up')
358            # self.__toggle_interfaces(dup_ifs)
359
360        for dual_if in self.if_mngr.get_dual_if_list(is_duplicated = False):
361            cache.add('IF', "{mode}ip nat inside".format( mode = unconfig_str ), dual_if.client_if.get_name())
362            cache.add('IF', "{mode}ip nat outside".format( mode = unconfig_str ), dual_if.server_if.get_name())
363            pool_id = dual_if.get_id() + 1
364
365            conf_t_command_set.append("{mode}ip nat pool pool{pool_num} {start_addr} {end_addr} netmask {mask}".format(
366                mode = unconfig_str,
367                pool_num = pool_id,
368                start_addr = pool_net,
369                end_addr = CNatConfig.calc_pool_end(pool_net, nat_obj.nat_netmask),
370                mask = nat_obj.nat_netmask))
371
372            conf_t_command_set.append("{mode}ip nat inside source list {num} pool pool{pool_num} overload".format(
373                mode = unconfig_str,
374                num = pool_id,
375                pool_num = pool_id ))
376            conf_t_command_set.append("{mode}access-list {num} permit {net_addr} {net_wildcard}".format(
377                mode = unconfig_str,
378                num = pool_id,
379                net_addr = client_net,
380                net_wildcard = nat_obj.client_acl_wildcard))
381
382            # bump up to the next client address
383            client_net = misc_methods.get_single_net_client_addr(client_net, nat_obj.net_increment)
384            pool_net   = misc_methods.get_single_net_client_addr(pool_net, nat_obj.net_increment)
385
386
387        # assign generated config list to cache
388        cache.add('CONF', conf_t_command_set)
389
390        # deploy the configs (order is important!)
391        return self.cmd_link.run_single_command( cache )
392
393
394    def config_no_nat (self, nat_obj = None):
395        # first, clear all nat translations
396        self.clear_nat_translations()
397
398        # then, decompose the known config
399        if nat_obj is None and self.nat_config is not None:
400            self.config_nat(self.nat_config, mode = 'unconfig')
401            self.nat_config = None  # reverse current NAT config back to None (no nat config is known to run).
402        elif nat_obj is not None:
403            self.config_nat(nat_obj, mode = 'unconfig')
404        else:
405            raise UserWarning('No NAT configuration is available for removal.')
406
407
408    def config_zbf (self, mode = 'config'):
409        cache               = CCommandCache()
410        pre_commit_cache    = CCommandCache()
411        conf_t_command_set  = []
412
413        # toggle all duplicate interfaces down
414        self.toggle_duplicated_intf(action = 'down')
415        # dup_ifs = self.if_mngr.get_duplicated_if()
416        # self.__toggle_interfaces(dup_ifs, action = 'down' )
417
418        # define security zones and security service policy to be applied on the interfaces
419        conf_t_command_set.append('class-map type inspect match-any c1')
420        conf_t_command_set.append('match protocol tcp')
421        conf_t_command_set.append('match protocol udp')
422        conf_t_command_set.append('policy-map type inspect p1')
423        conf_t_command_set.append('class type inspect c1')
424        conf_t_command_set.append('inspect')
425        conf_t_command_set.append('class class-default')
426        conf_t_command_set.append('pass')
427
428        conf_t_command_set.append('zone security z_in')
429        conf_t_command_set.append('zone security z_out')
430
431        conf_t_command_set.append('zone-pair security in2out source z_in destination z_out')
432        conf_t_command_set.append('service-policy type inspect p1')
433        conf_t_command_set.append('zone-pair security out2in source z_out destination z_in')
434        conf_t_command_set.append('service-policy type inspect p1')
435        conf_t_command_set.append('exit')
436
437        pre_commit_cache.add('CONF', conf_t_command_set)
438
439        for dual_if in self.if_mngr.get_dual_if_list(is_duplicated = False):
440            cache.add('IF', "zone-member security z_in", dual_if.client_if.get_name() )
441            cache.add('IF', "zone-member security z_out", dual_if.server_if.get_name() )
442
443        self.cmd_link.run_command( [pre_commit_cache, cache] )
444
445    def config_no_zbf (self):
446        cache               = CCommandCache()
447        conf_t_command_set  = []
448
449        # define security zones and security service policy to be applied on the interfaces
450        conf_t_command_set.append('no zone-pair security in2out source z_in destination z_out')
451        conf_t_command_set.append('no zone-pair security out2in source z_out destination z_in')
452
453        conf_t_command_set.append('no policy-map type inspect p1')
454        conf_t_command_set.append('no class-map type inspect match-any c1')
455
456        conf_t_command_set.append('no zone security z_in')
457        conf_t_command_set.append('no zone security z_out')
458
459        cache.add('CONF', conf_t_command_set)
460
461        for dual_if in self.if_mngr.get_dual_if_list(is_duplicated = False):
462            cache.add('IF', "no zone-member security z_in", dual_if.client_if.get_name() )
463            cache.add('IF', "no zone-member security z_out", dual_if.server_if.get_name() )
464
465        self.cmd_link.run_command( [cache] )
466        # toggle all duplicate interfaces back up
467        self.toggle_duplicated_intf(action = 'up')
468        # dup_ifs = self.if_mngr.get_duplicated_if()
469        # self.__toggle_interfaces(dup_ifs)
470
471
472    def config_ipv6_pbr (self, mode = 'config'):
473        idx = 1
474        unconfig_str = '' if mode=='config' else 'no '
475        cache               = CCommandCache()
476        conf_t_command_set  = []
477
478        conf_t_command_set.append('{mode}ipv6 unicast-routing'.format(mode = unconfig_str) )
479
480        for dual_if in self.if_mngr.get_dual_if_list():
481            client_if_command_set   = []
482            server_if_command_set   = []
483
484            client_net_next_hop = misc_methods.get_single_net_client_addr(dual_if.server_if.get_ipv6_addr(), {'7':1}, ip_type = 'ipv6' )
485            server_net_next_hop = misc_methods.get_single_net_client_addr(dual_if.client_if.get_ipv6_addr(), {'7':1}, ip_type = 'ipv6' )
486
487
488            client_if_command_set.append ('{mode}ipv6 enable'.format(mode = unconfig_str))
489            server_if_command_set.append ('{mode}ipv6 enable'.format(mode = unconfig_str))
490
491            if dual_if.is_duplicated():
492                prefix = 'ipv6_' + dual_if.get_vrf_name()
493            else:
494                prefix = 'ipv6'
495
496            # config interfaces with relevant route-map
497            client_if_command_set.append ('{mode}ipv6 policy route-map {pre}_{p1}_to_{p2}'.format(
498                mode = unconfig_str,
499                pre = prefix,
500                p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
501            server_if_command_set.append ('{mode}ipv6 policy route-map {pre}_{p2}_to_{p1}'.format(
502                mode = unconfig_str,
503                pre = prefix,
504                p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
505
506            # config global arp to interfaces net address and vrf
507            conf_t_command_set.append('{mode}ipv6 neighbor {next_hop} {intf} {dest_mac}'.format(
508                    mode = unconfig_str,
509                    next_hop = server_net_next_hop,
510                    intf = dual_if.client_if.get_name(),
511                    dest_mac = dual_if.client_if.get_dest_mac()))
512            conf_t_command_set.append('{mode}ipv6 neighbor {next_hop} {intf} {dest_mac}'.format(
513                    mode = unconfig_str,
514                    next_hop = client_net_next_hop,
515                    intf = dual_if.server_if.get_name(),
516                    dest_mac = dual_if.server_if.get_dest_mac()))
517
518            conf_t_command_set.append('{mode}route-map {pre}_{p1}_to_{p2} permit 10'.format(
519                    mode = unconfig_str,
520                    pre = prefix,
521                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
522            if (mode == 'config'):
523                conf_t_command_set.append('set ipv6 next-hop {next_hop}'.format(next_hop = client_net_next_hop ) )
524            conf_t_command_set.append('{mode}route-map {pre}_{p2}_to_{p1} permit 10'.format(
525                    mode = unconfig_str,
526                    pre = prefix,
527                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
528            if (mode == 'config'):
529                conf_t_command_set.append('set ipv6 next-hop {next_hop}'.format(next_hop = server_net_next_hop ) )
530                conf_t_command_set.append('exit')
531
532            # assign generated config list to cache
533            cache.add('IF', server_if_command_set, dual_if.server_if.get_name())
534            cache.add('IF', client_if_command_set, dual_if.client_if.get_name())
535            idx += 2
536
537        cache.add('CONF', conf_t_command_set)
538
539        # deploy the configs (order is important!)
540        self.cmd_link.run_command( [cache] )
541
542    def config_no_ipv6_pbr (self):
543        self.config_ipv6_pbr(mode = 'unconfig')
544
545    # show methods
546    def get_cpu_util (self):
547        response    = self.cmd_link.run_single_command('show platform hardware qfp active datapath utilization | inc Load')
548        return CShowParser.parse_cpu_util_stats(response)
549
550    def get_cft_stats (self):
551        response    = self.cmd_link.run_single_command('test platform hardware qfp active infrastructure cft datapath function cft-cpp-show-all-instances')
552        return CShowParser.parse_cft_stats(response)
553
554    def get_nbar_stats (self):
555        per_intf_stats = {}
556        for intf in self.if_mngr.get_if_list(if_type = IFType.Client):
557            response = self.cmd_link.run_single_command("show ip nbar protocol-discovery interface {interface} stats packet-count protocol".format( interface = intf.get_name() ), flush_first = True)
558            per_intf_stats[intf.get_name()] = CShowParser.parse_nbar_stats(response)
559        return per_intf_stats
560
561    def get_nbar_profiling_stats (self):
562        response = self.cmd_link.run_single_command("show platform hardware qfp active feature nbar profiling")
563        return CShowParser.parse_nbar_profiling_stats(response)
564
565    def get_drop_stats (self):
566
567        response    = self.cmd_link.run_single_command('show platform hardware qfp active interface all statistics', flush_first = True)
568        # print response
569        # response    = self.cmd_link.run_single_command('show platform hardware qfp active interface all statistics')
570        # print response
571        if_list_by_name = [x.get_name() for x in self.if_mngr.get_if_list()]
572        return CShowParser.parse_drop_stats(response, if_list_by_name )
573
574    def get_nat_stats (self):
575        response    = self.cmd_link.run_single_command('show ip nat statistics')
576        return CShowParser.parse_nat_stats(response)
577
578    def get_nat_trans (self):
579        return self.cmd_link.run_single_command('show ip nat translation')
580
581    def get_cvla_memory_usage(self):
582        response    = self.cmd_link.run_single_command('show platform hardware qfp active infrastructure cvla client handles')
583        # (res, res2) = CShowParser.parse_cvla_memory_usage(response)
584        return CShowParser.parse_cvla_memory_usage(response)
585
586
587    # clear methods
588    def clear_nat_translations(self):
589        pre_commit_cache = CCommandCache()
590        # prevent new NAT entries
591        # http://www.cisco.com/c/en/us/support/docs/ip/network-address-translation-nat/13779-clear-nat-comments.html
592        for dual_if in self.if_mngr.get_dual_if_list(is_duplicated = False):
593            pre_commit_cache.add('IF', "no ip nat inside", dual_if.client_if.get_name())
594            pre_commit_cache.add('IF', "no ip nat outside", dual_if.server_if.get_name())
595        # clear the translation
596        pre_commit_cache.add('EXEC', 'clear ip nat translation *')
597        self.cmd_link.run_single_command(pre_commit_cache)
598        time.sleep(1)
599
600    def clear_cft_counters (self):
601        """ clear_cft_counters(self) -> None
602
603        Clears the CFT counters on the platform
604        """
605        self.cmd_link.run_single_command('test platform hardware qfp active infrastructure cft datapath function cft-cpp-clear-instance-stats')
606
607    def clear_counters(self):
608        """ clear_counters(self) -> None
609
610        Clears the platform counters
611        """
612
613        pre_commit_cache = CCommandCache()
614        pre_commit_cache.add('EXEC', ['clear counters','\r'] )
615        self.cmd_link.run_single_command( pre_commit_cache )
616
617    def clear_nbar_stats(self):
618        """ clear_nbar_stats(self) -> None
619
620        Clears the NBAR-PD classification stats
621        """
622        pre_commit_cache = CCommandCache()
623        pre_commit_cache.add('EXEC', ['clear ip nbar protocol-discovery','\r'] )
624        self.cmd_link.run_single_command( pre_commit_cache )
625
626    def clear_packet_drop_stats(self):
627        """ clear_packet_drop_stats(self) -> None
628
629        Clears packet-drop stats
630        """
631#       command = "show platform hardware qfp active statistics drop clear"
632        self.cmd_link.run_single_command('show platform hardware qfp active interface all statistics clear_drop')
633
634    ###########################################
635    # file transfer and image loading methods #
636    ###########################################
637    def get_running_image_details (self):
638        """ get_running_image_details() -> dict
639
640        Check for the currently running image file on the platform.
641        Returns a dictionary, where 'drive' key is the drive in which the image is installed,
642        and 'image' key is the actual image file used.
643        """
644        response = self.cmd_link.run_single_command('show version | include System image')
645        parsed_info = CShowParser.parse_show_image_version(response)
646        self.running_image = parsed_info
647        return parsed_info
648
649
650    def check_image_existence (self, img_name):
651        """ check_image_existence(self, img_name) -> boolean
652
653        Parameters
654        ----------
655        img_name : str
656            a string represents the image name.
657
658        Check if the image file defined in the platform_config already loaded into the platform.
659        """
660        search_drives = ['bootflash', 'harddisk', self.running_image['drive']]
661        for search_drive in search_drives:
662            command = "dir {drive}: | include {image}".format(drive = search_drive, image = img_name)
663            response = self.cmd_link.run_single_command(command, timeout = 10)
664            if CShowParser.parse_image_existence(response, img_name):
665                self.needed_image_path = '%s:/%s' % (search_drive, img_name)
666                print('Found image in platform:', self.needed_image_path)
667                return True
668        return False
669
670    def config_tftp_server(self, device_cfg_obj, external_tftp_config = None, applyToPlatform = False):
671        """ configure_tftp_server(self, external_tftp_config, applyToPlatform) -> str
672
673        Parameters
674        ----------
675        external_tftp_config : dict (Not is use)
676            A path to external tftp config file other than using the one defined in the instance.
677        applyToPlatform : boolean
678            set to True in order to apply the config into the platform
679
680        Configures the tftp server on an interface of the platform.
681        """
682#       tmp_tftp_config = external_tftp_config if external_tftp_config is not None else self.tftp_server_config
683        self.tftp_cfg   = device_cfg_obj.get_tftp_info()
684        cache           = CCommandCache()
685
686        command = "ip tftp source-interface {intf}".format( intf = device_cfg_obj.get_mgmt_interface() )
687        cache.add('CONF', command )
688        self.cmd_link.run_single_command(cache)
689        self.config_history['tftp_server_config'] = True
690
691    def load_platform_image(self, img_filename, external_tftp_config = None):
692        """ load_platform_image(self, img_filename, external_tftp_config) -> None
693
694        Parameters
695        ----------
696        external_tftp_config : dict
697            A path to external tftp config file other than using the one defined in the instance.
698        img_filename : str
699            image name to be saved into the platforms drive.
700
701        This method loads the configured image into the platform's harddisk (unless it is already loaded),
702        and sets that image to be the boot_image of the platform.
703        """
704        if not self.check_image_existence(img_filename): # check if this image isn't already saved in platform
705            #tmp_tftp_config = external_tftp_config if external_tftp_config is not None else self.tftp_cfg
706
707            if self.config_history['tftp_server_config']:  # make sure a TFTP configuration has been loaded
708                cache = CCommandCache()
709                if self.running_image is None:
710                    self.get_running_image_details()
711
712                command = "copy tftp://{tftp_ip}/{img_path}/{image} bootflash:".format(
713                    tftp_ip  = self.tftp_cfg['ip_address'],
714                    img_path = self.tftp_cfg['images_path'],
715                    image    = img_filename)
716                cache.add('EXEC', [command, '\r', '\r'])
717
718                progress_thread = CProgressDisp.ProgressThread(notifyMessage = "Copying image via tftp, this may take a while...\n")
719                progress_thread.start()
720
721                response = self.cmd_link.run_single_command(cache, timeout = 900, read_until = ['\?', '\#'])
722                print("RESPONSE:")
723                print(response)
724                progress_thread.join()
725                copy_ok = CShowParser.parse_file_copy(response)
726
727                if not copy_ok:
728                    raise UserWarning('Image file loading failed. Please make sure the accessed image exists and has read privileges')
729            else:
730                raise UserWarning('TFTP configuration is not available. Please make sure a valid TFTP configuration has been provided')
731
732    def set_boot_image(self, boot_image):
733        """ set_boot_image(self, boot_image) -> None
734
735        Parameters
736        ----------
737        boot_image : str
738            An image file to be set as boot_image
739
740        Configures boot_image as the boot image of the platform into the running-config + config-register
741        """
742        cache = CCommandCache()
743        if self.needed_image_path is None:
744            if not self.check_image_existence(boot_image):
745                raise Exception("Trying to set boot image that's not found in router, please copy it first.")
746
747        boot_img_cmd = "boot system flash %s" % self.needed_image_path
748        config_register_cmd = "config-register 0x2021"
749        cache.add('CONF', ["no boot system", boot_img_cmd, config_register_cmd, '\r'])
750        response = self.cmd_link.run_single_command( cache )
751        print("RESPONSE:")
752        print(response)
753        self.save_config_to_startup_config()
754
755    def is_image_matches(self, needed_image):
756        """ set_boot_image(self, needed_image) -> boolean
757
758        Parameters
759        ----------
760        needed_image : str
761            An image file to compare router running image
762
763        Compares image name to router running image, returns match result.
764
765        """
766        if self.running_image is None:
767            self.get_running_image_details()
768        needed_image = needed_image.lower()
769        current_image = self.running_image['image'].lower()
770        if needed_image.find(current_image) != -1:
771            return True
772        if current_image.find(needed_image) != -1:
773            return True
774        return False
775
776    # misc class related methods
777
778    def load_platform_data_from_file (self, device_cfg_obj):
779        self.if_mngr.load_config(device_cfg_obj)
780
781    def launch_connection (self, device_cfg_obj):
782        self.running_image = None # clear the image name "cache"
783        self.cmd_link.launch_platform_connectivity(device_cfg_obj)
784
785    def reload_connection (self, device_cfg_obj):
786        self.cmd_link.close_platform_connection()
787        self.launch_connection(device_cfg_obj)
788
789    def save_config_to_startup_config (self):
790        """ save_config_to_startup_config(self) -> None
791
792        Copies running-config into startup-config.
793        """
794        cache = CCommandCache()
795        cache.add('EXEC', ['wr', '\r'] )
796        self.cmd_link.run_single_command(cache)
797
798    def reload_platform(self, device_cfg_obj):
799        """ reload_platform(self) -> None
800
801        Reloads the platform.
802        """
803        from subprocess import call
804        import os
805        i = 0
806        sleep_time = 30 # seconds
807
808        try:
809            cache = CCommandCache()
810
811            cache.add('EXEC', ['reload','n\r','\r'] )
812            self.cmd_link.run_single_command( cache )
813
814            progress_thread = CProgressDisp.ProgressThread(notifyMessage = "Reloading the platform, this may take a while...\n")
815            progress_thread.start()
816            time.sleep(60) # need delay for device to shut down before polling it
817            # poll the platform until ping response is received.
818            while True:
819                time.sleep(sleep_time)
820                try:
821                    x = call(["ping", "-c 1", device_cfg_obj.get_ip_address()], stdout = open(os.devnull, 'wb'))
822                except:
823                    x = 1
824                if x == 0:
825                    break
826                elif i > 20:
827                    raise TimeoutError('Platform failed to reload after reboot for over {minutes} minutes!'.format(minutes = round(1 + i * sleep_time / 60)))
828                else:
829                    i += 1
830
831            time.sleep(30)
832            self.reload_connection(device_cfg_obj)
833            progress_thread.join()
834        except Exception as e:
835            print(e)
836
837    def get_if_manager(self):
838        return self.if_mngr
839
840    def dump_obj_config (self, object_name):
841        if object_name=='nat' and self.nat_config is not None:
842            self.nat_config.dump_config()
843        elif object_name=='static_route' and self.stat_route_config is not None:
844            self.stat_route_config.dump_config()
845        else:
846            raise UserWarning('No known configuration exists.')
847
848    def toggle_duplicated_intf(self, action = 'down'):
849
850        dup_ifs = self.if_mngr.get_duplicated_if()
851        self.__toggle_interfaces( dup_ifs, action = action )
852
853
854    def __toggle_interfaces (self, intf_list, action = 'up'):
855        cache = CCommandCache()
856        mode_str = 'no ' if action == 'up' else ''
857
858        for intf_obj in intf_list:
859            cache.add('IF', '{mode}shutdown'.format(mode = mode_str), intf_obj.get_name())
860
861        self.cmd_link.run_single_command( cache )
862
863
864class CStaticRouteConfig(object):
865
866    def __init__(self, static_route_dict):
867        self.clients_start  = static_route_dict['clients_start']
868        self.servers_start  = static_route_dict['servers_start']
869        self.net_increment  = misc_methods.gen_increment_dict(static_route_dict['dual_port_mask'])
870        self.client_mask    = static_route_dict['client_destination_mask']
871        self.server_mask    = static_route_dict['server_destination_mask']
872        self.client_net_start = self.extract_net_addr(self.clients_start, self.client_mask)
873        self.server_net_start = self.extract_net_addr(self.servers_start, self.server_mask)
874        self.static_route_dict = static_route_dict
875
876    def extract_net_addr (self, ip_addr, ip_mask):
877        addr_lst = ip_addr.split('.')
878        mask_lst = ip_mask.split('.')
879        mask_lst = [str(int(x) & int(y)) for x, y in zip(addr_lst, mask_lst)]
880        return '.'.join(mask_lst)
881
882    def dump_config (self):
883        import yaml
884        print(yaml.dump( self.static_route_dict , default_flow_style=False))
885
886
887class CNatConfig(object):
888    def __init__(self, nat_dict):
889        self.clients_net_start  = nat_dict['clients_net_start']
890        self.client_acl_wildcard= nat_dict['client_acl_wildcard_mask']
891        self.net_increment      = misc_methods.gen_increment_dict(nat_dict['dual_port_mask'])
892        self.nat_pool_start     = nat_dict['pool_start']
893        self.nat_netmask        = nat_dict['pool_netmask']
894        self.nat_dict           = nat_dict
895
896    @staticmethod
897    def calc_pool_end (nat_pool_start, netmask):
898        pool_start_lst  = [int(x) for x in nat_pool_start.split('.')]
899        pool_end_lst    = list( pool_start_lst )   # create new list object, don't point to the original one
900        mask_lst        = [int(x) for x in netmask.split('.')]
901        curr_octet      = 3 # start with the LSB octet
902        inc_val         = 1
903
904        while True:
905            tmp_masked = inc_val & mask_lst[curr_octet]
906            if tmp_masked == 0:
907                if (inc_val << 1) > 255:
908                    inc_val = 1
909                    pool_end_lst[curr_octet] = 255
910                    curr_octet -= 1
911                else:
912                    inc_val <<= 1
913            else:
914                pool_end_lst[curr_octet] += (inc_val - 1)
915                break
916        return '.'.join([str(x) for x in pool_end_lst])
917
918    def dump_config (self):
919        import yaml
920        print(yaml.dump( self.nat_dict , default_flow_style=False))
921
922
923if __name__ == "__main__":
924    pass
925