From: Brian Candler Date: 2012-10-25T17:39:21+09:00 Subject: Re: Trying to convert some configuration files to a different output =begin A note about the structure: * a route map has a name and a list of entries * a route map entry has a priority (in Cisco world anyway), a list of matches, and a list of actions So let's make an object which holds the data for one route map entry =end class RouteMapEntry attr_accessor :priority, :conditions, :actions def initialize @priority = nil @conditions = [] @actions = [] end end =begin Parsing a single route map entry is pretty simple; we can use regular expressions to match the 'match' and 'set' lines, and convert them to the relevant Juniper form before storing them in a RouteMapEntry. For flexibility, we will write this parser so it assumes that the first line (the route-map header) has already been parsed, and it returns the first unparseable line. This allows us easily to assemble different parsers if we want to parse an entire Cisco config. =end def parse_cisco_routemap_entry(src, priority) rme = RouteMapEntry.new rme.priority = priority loop do line = src.gets line.strip! if line # remove leading/trailing whitespace case line when /^match as-path (\d+)$/ rme.conditions << "as-path in aspath#{$1}" when /^match ip address prefix-list (\S+)$/ rme.conditions << "destination in #{$1}" when /^set local-preference (\d+)$/ rme.actions << "set local-preference #{$1}" when /^set community (.*)$/ rme.actions << "set community (#{$1})" # add more here as required else # EOF or any unrecognised line terminates this routemap entry return [rme, line] end end end =begin So now we parse a whole series of routemaps. In general a config may have multiple named routemaps, so we build a hash of them. =end def parse_cisco_routemaps(src) routemaps = {} # {"name" => [RouteMapEntry, RouteMapEntry, ...]} line = src.gets while line line.strip! # remove leading/trailing whitespace case line when /^!/, /^\s*$/ # skip comment or empty line line = src.gets when /^route-map (\S+) permit (\d+)$/ name, priority = $1, $2.to_i rme, line = parse_cisco_routemap_entry(src, priority) routemaps[name] ||= [] routemaps[name] << rme else $stderr.puts "Unrecognized line: #{line.inspect}" line = src.gets end end return routemaps end =begin We need to be able to assemble a list of routemaps into Juniper form =end def write_juniper_routemaps(routemaps, dest=$stdout) routemaps.each do |name,routemap_entries| dest << "route-policy #{name}\n" dest << " apply bogons\n" routemap_entries = routemap_entries.sort_by { |e| e.priority } cond = "if" routemap_entries.each do |rme| if rme.conditions.empty? dest << " else\n" else dest << " #{cond} #{rme.conditions.join(" and ")} then\n" end rme.actions.each do |action| dest << " #{action}\n" end break if rme.conditions.empty? cond = "elseif" end dest << " endif\n" dest << "end-policy\n" end end # Testing src = <