Merge branch 'pull/134' with changes

One commit reverted.

Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
This commit is contained in:
David Lamparter 2017-01-31 13:53:15 +01:00
commit e08f1a05f2
8 changed files with 241 additions and 30 deletions

7
.gitignore vendored
View File

@ -60,3 +60,10 @@ cscope.*
*.pb.h
*.pb-c.h
*.pb-c.c
TAGS
tags
GTAGS
GSYMS
GRTAGS
GPATH

View File

@ -171,6 +171,9 @@ bgp_bfd_deregister_peer (struct peer *peer)
if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
return;
bfd_info->status = BFD_STATUS_DOWN;
bfd_info->last_update = bgp_clock();
bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER);
}
@ -311,14 +314,14 @@ bgp_bfd_dest_update (int command, struct zclient *zclient,
prefix2str(&dp, buf[0], sizeof(buf[0]));
if (ifp)
{
zlog_debug("Zebra: interface %s bfd destination %s %s",
ifp->name, buf[0], bfd_get_status_str(status));
zlog_debug("Zebra: vrf %d interface %s bfd destination %s %s",
vrf_id, ifp->name, buf[0], bfd_get_status_str(status));
}
else
{
prefix2str(&sp, buf[1], sizeof(buf[1]));
zlog_debug("Zebra: source %s bfd destination %s %s",
buf[1], buf[0], bfd_get_status_str(status));
zlog_debug("Zebra: vrf %d source %s bfd destination %s %s",
vrf_id, buf[1], buf[0], bfd_get_status_str(status));
}
}

View File

@ -4714,6 +4714,7 @@ peer_update_source_vty (struct vty *vty, const char *peer_str,
const char *source_str)
{
struct peer *peer;
struct prefix p;
peer = peer_and_group_lookup_vty (vty, peer_str);
if (! peer)
@ -4730,7 +4731,16 @@ peer_update_source_vty (struct vty *vty, const char *peer_str,
if (ret == 0)
peer_update_source_addr_set (peer, &su);
else
peer_update_source_if_set (peer, source_str);
{
if (str2prefix (source_str, &p))
{
vty_out (vty, "%% Invalid update-source, remove prefix length %s",
VTY_NEWLINE);
return CMD_WARNING;
}
else
peer_update_source_if_set (peer, source_str);
}
}
else
peer_update_source_unset (peer);
@ -11907,11 +11917,19 @@ bgp_show_peer (struct vty *vty, struct peer *p, u_char use_json, json_object *js
tm = gmtime(&uptime);
json_object_int_add(json_neigh, "lastResetTimerMsecs", (tm->tm_sec * 1000) + (tm->tm_min * 60000) + (tm->tm_hour * 3600000));
json_object_string_add(json_neigh, "lastResetDueTo", peer_down_str[(int) p->last_reset]);
if (p->last_reset_cause_size)
if (p->last_reset == PEER_DOWN_NOTIFY_SEND ||
p->last_reset == PEER_DOWN_NOTIFY_RECEIVED)
{
char errorcodesubcode_hexstr[5];
char errorcodesubcode_str[256];
code_str = bgp_notify_code_str(p->notify.code);
subcode_str = bgp_notify_subcode_str(p->notify.code, p->notify.subcode);
sprintf(errorcodesubcode_hexstr, "%02X%02X", p->notify.code, p->notify.subcode);
json_object_string_add(json_neigh, "lastErrorCodeSubcode", errorcodesubcode_hexstr);
snprintf(errorcodesubcode_str, 255, "%s%s", code_str, subcode_str);
json_object_string_add(json_neigh, "lastNotificationReason", errorcodesubcode_str);
}
}
else

View File

@ -6680,26 +6680,27 @@ bgp_config_write_peer_global (struct vty *vty, struct bgp *bgp,
}
/* advertisement-interval */
if (CHECK_FLAG (peer->config, PEER_CONFIG_ROUTEADV)
&& peer->v_routeadv != BGP_DEFAULT_EBGP_ROUTEADV
&& ! peer_group_active (peer))
if (CHECK_FLAG (peer->config, PEER_CONFIG_ROUTEADV) &&
((! peer_group_active (peer) && peer->v_routeadv != BGP_DEFAULT_EBGP_ROUTEADV) ||
(peer_group_active (peer) && peer->v_routeadv != g_peer->v_routeadv)))
{
vty_out (vty, " neighbor %s advertisement-interval %d%s",
addr, peer->v_routeadv, VTY_NEWLINE);
}
/* timers */
if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)
&& (peer->keepalive != BGP_DEFAULT_KEEPALIVE || peer->holdtime != BGP_DEFAULT_HOLDTIME)
&& ! peer_group_active (peer))
if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER) &&
((! peer_group_active (peer) && (peer->keepalive != BGP_DEFAULT_KEEPALIVE || peer->holdtime != BGP_DEFAULT_HOLDTIME)) ||
(peer_group_active (peer) && (peer->keepalive != g_peer->keepalive || peer->holdtime != g_peer->holdtime))))
{
vty_out (vty, " neighbor %s timers %d %d%s", addr,
peer->keepalive, peer->holdtime, VTY_NEWLINE);
}
if (CHECK_FLAG (peer->config, PEER_CONFIG_CONNECT) &&
peer->connect != BGP_DEFAULT_CONNECT_RETRY &&
! peer_group_active (peer))
((! peer_group_active (peer) && peer->connect != BGP_DEFAULT_CONNECT_RETRY) ||
(peer_group_active (peer) && peer->connect != g_peer->connect)))
{
vty_out (vty, " neighbor %s timers connect %d%s", addr,
peer->connect, VTY_NEWLINE);

View File

@ -38,7 +38,7 @@ import string
import subprocess
import sys
from collections import OrderedDict
from ipaddr import IPv6Address
from ipaddr import IPv6Address, IPNetwork
from pprint import pformat
@ -173,6 +173,100 @@ class Config(object):
if not key:
return
'''
IP addresses specified in "network" statements, "ip prefix-lists"
etc. can differ in the host part of the specification the user
provides and what the running config displays. For example, user
can specify 11.1.1.1/24, and the running config displays this as
11.1.1.0/24. Ensure we don't do a needless operation for such
lines. IS-IS & OSPFv3 have no "network" support.
'''
re_key_rt = re.match(r'(ip|ipv6)\s+route\s+([A-Fa-f:.0-9/]+)(.*)$', key[0])
if re_key_rt:
addr = re_key_rt.group(2)
if '/' in addr:
try:
newaddr = IPNetwork(addr)
key[0] = '%s route %s/%s%s' % (re_key_rt.group(1),
newaddr.network,
newaddr.prefixlen,
re_key_rt.group(3))
except ValueError:
pass
re_key_rt = re.match(
r'(ip|ipv6)\s+prefix-list(.*)(permit|deny)\s+([A-Fa-f:.0-9/]+)(.*)$',
key[0]
)
if re_key_rt:
addr = re_key_rt.group(4)
if '/' in addr:
try:
newaddr = '%s/%s' % (IPNetwork(addr).network,
IPNetwork(addr).prefixlen)
except ValueError:
newaddr = addr
else:
newaddr = addr
legestr = re_key_rt.group(5)
re_lege = re.search(r'(.*)le\s+(\d+)\s+ge\s+(\d+)(.*)', legestr)
if re_lege:
legestr = '%sge %s le %s%s' % (re_lege.group(1),
re_lege.group(3),
re_lege.group(2),
re_lege.group(4))
re_lege = re.search(r'(.*)ge\s+(\d+)\s+le\s+(\d+)(.*)', legestr)
if (re_lege and ((re_key_rt.group(1) == "ip" and
re_lege.group(3) == "32") or
(re_key_rt.group(1) == "ipv6" and
re_lege.group(3) == "128"))):
legestr = '%sge %s%s' % (re_lege.group(1),
re_lege.group(2),
re_lege.group(4))
key[0] = '%s prefix-list%s%s %s%s' % (re_key_rt.group(1),
re_key_rt.group(2),
re_key_rt.group(3),
newaddr,
legestr)
if lines and key[0].startswith('router bgp'):
newlines = []
for line in lines:
re_net = re.match(r'network\s+([A-Fa-f:.0-9/]+)(.*)$', line)
if re_net:
addr = re_net.group(1)
if '/' not in addr and key[0].startswith('router bgp'):
# This is most likely an error because with no
# prefixlen, BGP treats the prefixlen as 8
addr = addr + '/8'
try:
newaddr = IPNetwork(addr)
line = 'network %s/%s %s' % (newaddr.network,
newaddr.prefixlen,
re_net.group(2))
newlines.append(line)
except ValueError:
# Really this should be an error. Whats a network
# without an IP Address following it ?
newlines.append(line)
else:
newlines.append(line)
lines = newlines
'''
More fixups in user specification and what running config shows.
"null0" in routes must be replaced by Null0, and "blackhole" must
be replaced by Null0 as well.
'''
if (key[0].startswith('ip route') or key[0].startswith('ipv6 route') and
'null0' in key[0] or 'blackhole' in key[0]):
key[0] = re.sub(r'\s+null0(\s*$)', ' Null0', key[0])
key[0] = re.sub(r'\s+blackhole(\s*$)', ' Null0', key[0])
if lines:
if tuple(key) not in self.contexts:
ctx = Context(tuple(key), lines)
@ -437,16 +531,25 @@ def get_normalized_ipv6_line(line):
"""
Return a normalized IPv6 line as produced by frr,
with all letters in lower case and trailing and leading
zeros removed
zeros removed, and only the network portion present if
the IPv6 word is a network
"""
norm_line = ""
words = line.split(' ')
for word in words:
if ":" in word:
try:
norm_word = str(IPv6Address(word)).lower()
except:
norm_word = word
norm_word = None
if "/" in word:
try:
v6word = IPNetwork(word)
norm_word = '%s/%s' % (v6word.network, v6word.prefixlen)
except ValueError:
pass
if not norm_word:
try:
norm_word = '%s' % IPv6Address(word)
except ValueError:
norm_word = word
else:
norm_word = word
norm_line = norm_line + " " + norm_word
@ -579,6 +682,60 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
lines_to_add_to_del.append((ctx_keys, swpx_interface))
lines_to_add_to_del.append((tmp_ctx_keys, swpx_remoteas))
'''
In 3.0, we made bgp bestpath multipath as-relax command
automatically assume no-as-set since the lack of this option caused
weird routing problems and this problem was peculiar to this
implementation. When the running config is shown in relases after
3.0, the no-as-set is not shown as its the default. This causes
reload to unnecessarily unapply this option to only apply it back
again, causing unnecessary session resets. Handle this.
'''
if ctx_keys[0].startswith('router bgp') and line and 'multipath-relax' in line:
re_asrelax_new = re.search('^bgp\s+bestpath\s+as-path\s+multipath-relax$', line)
old_asrelax_cmd = 'bgp bestpath as-path multipath-relax no-as-set'
found_asrelax_old = line_exist(lines_to_add, ctx_keys, old_asrelax_cmd)
if re_asrelax_new and found_asrelax_old:
deleted = True
lines_to_del_to_del.append((ctx_keys, line))
lines_to_add_to_del.append((ctx_keys, old_asrelax_cmd))
'''
More old-to-new config handling. ip import-table no longer accepts
distance, but we honor the old syntax. But 'show running' shows only
the new syntax. This causes an unnecessary 'no import-table' followed
by the same old 'ip import-table' which causes perturbations in
announced routes leading to traffic blackholes. Fix this issue.
'''
re_importtbl = re.search('^ip\s+import-table\s+(\d+)$', ctx_keys[0])
if re_importtbl:
table_num = re_importtbl.group(1)
for ctx in lines_to_add:
if ctx[0][0].startswith('ip import-table %s distance' % table_num):
lines_to_del_to_del.append((('ip import-table %s' % table_num,), None))
lines_to_add_to_del.append((ctx[0], None))
'''
ip/ipv6 prefix-list can be specified without a seq number. However,
the running config always adds 'seq x', where x is a number incremented
by 5 for every element, to the prefix list. So, ignore such lines as
well. Sample prefix-list lines:
ip prefix-list PR-TABLE-2 seq 5 permit 20.8.2.0/24 le 32
ip prefix-list PR-TABLE-2 seq 10 permit 20.8.2.0/24 le 32
ipv6 prefix-list vrfdev6-12 permit 2000:9:2::/64 gt 64
'''
re_ip_pfxlst = re.search('^(ip|ipv6)(\s+prefix-list\s+)(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$',
ctx_keys[0])
if re_ip_pfxlst:
tmpline = (re_ip_pfxlst.group(1) + re_ip_pfxlst.group(2) +
re_ip_pfxlst.group(3) + re_ip_pfxlst.group(5) +
re_ip_pfxlst.group(6))
for ctx in lines_to_add:
if ctx[0][0] == tmpline:
lines_to_del_to_del.append((ctx_keys, None))
lines_to_add_to_del.append(((tmpline,), None))
if not deleted:
found_add_line = line_exist(lines_to_add, ctx_keys, line)
@ -646,6 +803,11 @@ def compare_context_objects(newconf, running):
delete_bgpd = True
lines_to_del.append((running_ctx_keys, None))
# We cannot do 'no interface' in quagga, and so deal with it
elif running_ctx_keys[0].startswith('interface'):
for line in running_ctx.lines:
lines_to_del.append((running_ctx_keys, line))
# If this is an address-family under 'router bgp' and we are already deleting the
# entire 'router bgp' context then ignore this sub-context
elif "router bgp" in running_ctx_keys[0] and len(running_ctx_keys) > 1 and delete_bgpd:
@ -697,6 +859,7 @@ if __name__ == '__main__':
parser.add_argument('--debug', action='store_true', help='Enable debugs', default=False)
parser.add_argument('--stdout', action='store_true', help='Log to STDOUT', default=False)
parser.add_argument('filename', help='Location of new frr config file')
parser.add_argument('--overwrite', action='store_true', help='Overwrite Quagga.conf with running config output', default=False)
args = parser.parse_args()
# Logging
@ -904,5 +1067,6 @@ if __name__ == '__main__':
subprocess.call(['/usr/bin/vtysh', '-f', filename])
os.unlink(filename)
# Make these changes persistent
# Make these changes persistent
if args.overwrite or args.filename != '/etc/quagga/Quagga.conf':
subprocess.call(['/usr/bin/vtysh', '-c', 'write'])

View File

@ -736,8 +736,10 @@ _netlink_route_build_singlepath(
if (nexthop->type == NEXTHOP_TYPE_IPV4
|| nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
{
_netlink_route_nl_add_gateway_info (rtmsg->rtm_family, AF_INET, nlmsg,
req_size, bytelen, nexthop);
/* Send deletes to the kernel without specifying the next-hop */
if (cmd != RTM_DELROUTE)
_netlink_route_nl_add_gateway_info (rtmsg->rtm_family, AF_INET, nlmsg,
req_size, bytelen, nexthop);
if (cmd == RTM_NEWROUTE)
{

View File

@ -459,6 +459,7 @@ zebra_ptm_handle_bfd_msg(void *arg, void *in_ctxt, struct interface *ifp)
char vrf_str[64];
struct prefix dest_prefix;
struct prefix src_prefix;
vrf_id_t vrf_id;
ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDSTATUS_STR, bfdst_str);
@ -491,7 +492,8 @@ zebra_ptm_handle_bfd_msg(void *arg, void *in_ctxt, struct interface *ifp)
}
if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug("%s: Recv Port [%s] bfd status [%s] vrf [%s] peer [%s] local [%s]",
zlog_debug("%s: Recv Port [%s] bfd status [%s] vrf [%s]"
" peer [%s] local [%s]",
__func__, ifp ? ifp->name : "N/A", bfdst_str,
vrf_str, dest_str, src_str);
@ -510,12 +512,18 @@ zebra_ptm_handle_bfd_msg(void *arg, void *in_ctxt, struct interface *ifp)
}
}
if (!strcmp(ZEBRA_PTM_INVALID_VRF, vrf_str) && ifp) {
vrf_id = ifp->vrf_id;
} else {
vrf_id = vrf_name_to_id(vrf_str);
}
if (!strcmp (bfdst_str, ZEBRA_PTM_BFDSTATUS_DOWN_STR)) {
if_bfd_session_update(ifp, &dest_prefix, &src_prefix, BFD_STATUS_DOWN,
vrf_name_to_id(vrf_str));
vrf_id);
} else {
if_bfd_session_update(ifp, &dest_prefix, &src_prefix, BFD_STATUS_UP,
vrf_name_to_id(vrf_str));
vrf_id);
}
return 0;

View File

@ -791,7 +791,7 @@ ALIAS (no_ip_route,
"Emit an ICMP unreachable when matched\n"
"Silently discard pkts when matched\n")
ALIAS (no_ip_route_tag,
DEFUN (no_ip_route_flags_tag,
no_ip_route_flags_tag_cmd,
"no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>",
NO_STR
@ -804,6 +804,10 @@ ALIAS (no_ip_route_tag,
"Silently discard pkts when matched\n"
"Tag of this route\n"
"Tag value\n")
{
return zebra_static_ipv4 (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], argv[2], argv[3],
NULL, NULL, NULL);
}
DEFUN (no_ip_route_flags2,
no_ip_route_flags2_cmd,
@ -831,7 +835,7 @@ DEFUN (no_ip_route_flags2_tag,
"Tag of this route\n"
"Tag value\n")
{
return zebra_static_ipv4 (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, NULL, argv[1],
return zebra_static_ipv4 (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, NULL, argv[2],
NULL, NULL, NULL);
}
@ -882,7 +886,7 @@ ALIAS (no_ip_route_mask,
"Emit an ICMP unreachable when matched\n"
"Silently discard pkts when matched\n")
ALIAS (no_ip_route_mask_tag,
DEFUN (no_ip_route_mask_flags_tag,
no_ip_route_mask_flags_tag_cmd,
"no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>",
NO_STR
@ -896,6 +900,10 @@ ALIAS (no_ip_route_mask_tag,
"Silently discard pkts when matched\n"
"Tag of this route\n"
"Tag value\n")
{
return zebra_static_ipv4 (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], NULL, argv[4],
NULL, NULL, NULL);
}
DEFUN (no_ip_route_mask_flags2,
no_ip_route_mask_flags2_cmd,
@ -925,7 +933,7 @@ DEFUN (no_ip_route_mask_flags2_tag,
"Tag of this route\n"
"Tag value\n")
{
return zebra_static_ipv4 (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL, NULL, argv[2],
return zebra_static_ipv4 (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL, NULL, argv[3],
NULL, NULL, NULL);
}