1
- # Copyright (c) 2015-2016 Cisco and/or its affiliates.
1
+ # Copyright (c) 2015-2018 Cisco and/or its affiliates.
2
2
#
3
3
# Licensed under the Apache License, Version 2.0 (the "License");
4
4
# you may not use this file except in compliance with the License.
12
12
# See the License for the specific language governing permissions and
13
13
# limitations under the License.
14
14
15
+ require 'ipaddr'
15
16
require_relative 'node_util'
16
17
17
18
module Cisco
@@ -73,6 +74,9 @@ def ace_get
73
74
remark = Regexp . new ( '(?<seqno>\d+) remark (?<remark>.*)' ) . match ( str )
74
75
return remark unless remark . nil?
75
76
77
+ # specialized icmp protocol handling
78
+ return icmp_ace_get ( str ) if str . include? ( 'icmp' )
79
+
76
80
# rubocop:disable Metrics/LineLength
77
81
regexp = Regexp . new ( '(?<seqno>\d+) (?<action>\S+)' \
78
82
' *(?<proto>\d+|\S+)' \
@@ -95,6 +99,60 @@ def ace_get
95
99
regexp . match ( str )
96
100
end
97
101
102
+ # icmp ace getter
103
+ def icmp_ace_get ( str )
104
+ # rubocop:disable Metrics/LineLength
105
+ # fragments is nvgen at a different location than all other
106
+ # proto_option so get rid of it so as not to mess up other fields
107
+ str . sub! ( 'fragments ' , '' )
108
+ regexp = Regexp . new ( '(?<seqno>\d+) (?<action>\S+)' \
109
+ ' *(?<proto>\d+|\S+)' \
110
+ ' *(?<src_addr>any|host \S+|[:\.0-9a-fA-F]+ [:\.0-9a-fA-F]+|[:\.0-9a-fA-F]+\/\d+|addrgroup \S+)' \
111
+ ' *(?<dst_addr>any|host \S+|[:\.0-9a-fA-F]+ [:\.0-9a-fA-F]+|[:\.0-9a-fA-F]+\/\d+|addrgroup \S+)' \
112
+ ' *(?<proto_option>\S+)?' \
113
+ ' *(?<precedence>precedence \S+)?' \
114
+ ' *(?<dscp>dscp \S+)?' \
115
+ ' *(?<time_range>time-range \S+)?' \
116
+ ' *(?<packet_length>packet-length (range \d+ \d+|(lt|eq|gt|neq) \d+))?' \
117
+ ' *(?<ttl>ttl \d+)?' \
118
+ ' *(?<vlan>vlan \d+)?' \
119
+ ' *(?<set_erspan_gre_proto>set-erspan-gre-proto \d+)?' \
120
+ ' *(?<set_erspan_dscp>set-erspan-dscp \d+)?' \
121
+ ' *(?<redirect>redirect \S+)?' )
122
+ regexp_no_proto_option = Regexp . new ( '(?<seqno>\d+) (?<action>\S+)' \
123
+ ' *(?<proto>\d+|\S+)' \
124
+ ' *(?<src_addr>any|host \S+|[:\.0-9a-fA-F]+ [:\.0-9a-fA-F]+|[:\.0-9a-fA-F]+\/\d+|addrgroup \S+)' \
125
+ ' *(?<dst_addr>any|host \S+|[:\.0-9a-fA-F]+ [:\.0-9a-fA-F]+|[:\.0-9a-fA-F]+\/\d+|addrgroup \S+)' \
126
+ ' *(?<precedence>precedence \S+)?' \
127
+ ' *(?<dscp>dscp \S+)?' \
128
+ ' *(?<time_range>time-range \S+)?' \
129
+ ' *(?<packet_length>packet-length (range \d+ \d+|(lt|eq|gt|neq) \d+))?' \
130
+ ' *(?<ttl>ttl \d+)?' \
131
+ ' *(?<vlan>vlan \d+)?' \
132
+ ' *(?<set_erspan_gre_proto>set-erspan-gre-proto \d+)?' \
133
+ ' *(?<set_erspan_dscp>set-erspan-dscp \d+)?' \
134
+ ' *(?<redirect>redirect \S+)?' )
135
+ temp = regexp . match ( str )
136
+ po = temp [ :proto_option ]
137
+ if po . nil?
138
+ return temp
139
+ # redirect can be proto_option or an actual redirect to interface
140
+ elsif po . strip . match ( /redirect$/ )
141
+ if str . match ( /Ethernet|port-channel/ )
142
+ # if proto_option is given as redirect and also redirect to intf
143
+ # we need to do extra processing
144
+ return temp if check_redirect_repeat ( str )
145
+ return regexp_no_proto_option . match ( str )
146
+ end
147
+ # the reserved keywords check
148
+ elsif po . strip . match ( /precedence$|dscp$|time-range$|packet-length$|ttl$|vlan$|set-erspan-gre-proto$|set-erspan-dscp$|log$/ )
149
+ return regexp_no_proto_option . match ( str )
150
+ else
151
+ return temp
152
+ end
153
+ # rubocop:enable Metrics/LineLength
154
+ end
155
+
98
156
# common ace setter. Put the values you need in a hash and pass it in.
99
157
# attrs = {:action=>'permit', :proto=>'tcp', :src =>'host 1.1.1.1'}
100
158
def ace_set ( attrs )
@@ -130,6 +188,10 @@ def ace_set(attrs)
130
188
:tcp_option_length ,
131
189
:redirect ,
132
190
:log ,
191
+ :proto_option ,
192
+ :set_erspan_dscp ,
193
+ :set_erspan_gre_proto ,
194
+ :vlan ,
133
195
] . each do |p |
134
196
attrs [ p ] = '' if attrs [ p ] . nil?
135
197
send ( p . to_s + '=' , attrs [ p ] )
@@ -139,6 +201,21 @@ def ace_set(attrs)
139
201
config_set ( 'acl' , cmd , @set_args )
140
202
end
141
203
204
+ def valid_ipv6? ( addr )
205
+ begin
206
+ ret = IPAddr . new ( addr . split [ 0 ] ) . ipv6?
207
+ rescue
208
+ ret = false
209
+ end
210
+ ret
211
+ end
212
+
213
+ def check_redirect_repeat ( str )
214
+ return false unless str . include? ( 'redirect' )
215
+ nstr = str . sub ( 'redirect' , '' ) . strip
216
+ nstr . include? ( 'redirect' ) ? true : false
217
+ end
218
+
142
219
# PROPERTIES
143
220
# ----------
144
221
def seqno
@@ -182,7 +259,7 @@ def src_addr
182
259
return nil if match . nil? || !match . names . include? ( 'src_addr' )
183
260
addr = match [ :src_addr ]
184
261
# Normalize addr. Some platforms zero_pad ipv6 addrs.
185
- addr . gsub! ( /^0*/ , '' ) . gsub! ( /:0*/ , ':' )
262
+ addr . gsub! ( /^0*/ , '' ) . gsub! ( /:0*/ , ':' ) if valid_ipv6? ( addr )
186
263
addr
187
264
end
188
265
@@ -205,7 +282,7 @@ def dst_addr
205
282
return nil if match . nil? || !match . names . include? ( 'dst_addr' )
206
283
addr = match [ :dst_addr ]
207
284
# Normalize addr. Some platforms zero_pad ipv6 addrs.
208
- addr . gsub! ( /^0*/ , '' ) . gsub! ( /:0*/ , ':' )
285
+ addr . gsub! ( /^0*/ , '' ) . gsub! ( /:0*/ , ':' ) if valid_ipv6? ( addr )
209
286
addr
210
287
end
211
288
@@ -261,6 +338,49 @@ def dscp=(dscp)
261
338
@set_args [ :dscp ] = Utils . attach_prefix ( dscp , :dscp )
262
339
end
263
340
341
+ def vlan
342
+ Utils . extract_value ( ace_get , 'vlan' )
343
+ end
344
+
345
+ def vlan = ( vlan )
346
+ @set_args [ :vlan ] = Utils . attach_prefix ( vlan , :vlan )
347
+ end
348
+
349
+ def set_erspan_dscp
350
+ ret = Utils . extract_value ( ace_get , 'set_erspan_dscp' , 'set-erspan-dscp' )
351
+ return ret if ret
352
+ # position of set_erspan_dscp is different in older release so check again
353
+ str = config_get ( 'acl' , 'ace' , @get_args )
354
+ sstr = str . split
355
+ return sstr [ sstr . index ( 'set-erspan-dscp' ) + 1 ] if
356
+ sstr . include? ( 'set-erspan-dscp' )
357
+ end
358
+
359
+ def set_erspan_dscp = ( set_erspan_dscp )
360
+ @set_args [ :set_erspan_dscp ] = Utils . attach_prefix ( set_erspan_dscp ,
361
+ :set_erspan_dscp ,
362
+ 'set-erspan-dscp' )
363
+ end
364
+
365
+ def set_erspan_gre_proto
366
+ ret = Utils . extract_value ( ace_get , 'set_erspan_gre_proto' ,
367
+ 'set-erspan-gre-proto' )
368
+ return ret if ret
369
+ # position of set_erspan_gre_proto is different in older release
370
+ # so check again
371
+ str = config_get ( 'acl' , 'ace' , @get_args )
372
+ sstr = str . split
373
+ return sstr [ sstr . index ( 'set-erspan-gre-proto' ) + 1 ] if
374
+ sstr . include? ( 'set-erspan-gre-proto' )
375
+ end
376
+
377
+ def set_erspan_gre_proto = ( set_erspan_gre_proto )
378
+ @set_args [ :set_erspan_gre_proto ] =
379
+ Utils . attach_prefix ( set_erspan_gre_proto ,
380
+ :set_erspan_gre_proto ,
381
+ 'set-erspan-gre-proto' )
382
+ end
383
+
264
384
def time_range
265
385
Utils . extract_value ( ace_get , 'time_range' , 'time-range' )
266
386
end
@@ -317,12 +437,27 @@ def redirect=(redirect)
317
437
@set_args [ :redirect ] = Utils . attach_prefix ( redirect , :redirect )
318
438
end
319
439
320
- def log
440
+ def proto_option
321
441
match = ace_get
442
+ return nil if match . nil? || proto != 'icmp' || !remark . nil?
443
+ # fragments is nvgen at a different location than all other
444
+ # proto_option
445
+ if config_get ( 'acl' , 'ace' , @get_args ) . include? ( 'fragments' )
446
+ return 'fragments'
447
+ end
448
+ # log is special case
449
+ return nil if !match . names . include? ( 'proto_option' ) ||
450
+ match [ :proto_option ] == 'log'
451
+ match [ :proto_option ]
452
+ end
453
+
454
+ def proto_option = ( proto_option )
455
+ @set_args [ :proto_option ] = proto_option
456
+ end
457
+
458
+ def log
322
459
return nil unless remark . nil?
323
- return false if match . nil?
324
- return false unless match . names . include? ( 'log' )
325
- match [ :log ] == 'log' ? true : false
460
+ config_get ( 'acl' , 'ace' , @get_args ) . include? ( 'log' ) ? true : false
326
461
end
327
462
328
463
def log = ( log )
0 commit comments