diff --git a/lib/vrf.c b/lib/vrf.c index dd015e0413..b85ce63f9b 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -80,94 +80,182 @@ vrf_build_key (vrf_id_t vrf_id, struct prefix *p) } /* Get a VRF. If not found, create one. - * Arg: name + * Arg: + * name - The name of the vrf. May be NULL if unknown. + * vrf_id - The vrf_id of the vrf. May be VRF_UNKNOWN if unknown * Description: Please note that this routine can be called with just the name - and 0 vrf-id */ + * and 0 vrf-id + */ struct vrf * vrf_get (vrf_id_t vrf_id, const char *name) { struct prefix p; struct route_node *rn = NULL; struct vrf *vrf = NULL; - size_t namelen = 0; - /* Only create a route node if the vrf was learned from the kernel */ - if (vrf_id != VRF_UNKNOWN) + if (debug_vrf) + zlog_debug ("VRF_GET: %s(%d)", name, vrf_id); + + /* + * Nothing to see, move along here + */ + if (!name && vrf_id == VRF_UNKNOWN) + return NULL; + + /* + * Valid vrf name and unknown vrf_id case + * + * This is called when we are configured from + * the cli but we have no kernel information yet. + */ + if (name && vrf_id == VRF_UNKNOWN) { - vrf_build_key (vrf_id, &p); - rn = route_node_get (vrf_table, &p); - - if (rn->info) - { - vrf = (struct vrf *)rn->info; - route_unlock_node (rn); /* get */ - - if (name) - { - strncpy (vrf->name, name, strlen(name)); - vrf->name[strlen(name)] = '\0'; - if (vrf_list_lookup_by_name (vrf->name) == NULL) - listnode_add_sort (vrf_list, vrf); - } - if (debug_vrf) - zlog_debug ("VRF(%u) %s Found %p", vrf_id, (name) ? name : "(NULL)", - vrf); - } - } - - if (name && !vrf) - vrf = vrf_list_lookup_by_name(name); - - if (vrf) - { - if (debug_vrf) - zlog_debug ("VRF(%u) %s lookup by name is successful", - vrf_id, (name) ? name : "(NULL)"); - } - else - { - if (name) - { - namelen = strlen (name); - if (namelen > VRF_NAMSIZ) - { - zlog_err("Attempt to get/create VRF %u name %s - name too long", - vrf_id, name); - return NULL; - } - } + vrf = vrf_list_lookup_by_name (name); + if (vrf) + return vrf; vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf)); if (debug_vrf) zlog_debug ("VRF(%u) %s is created.", vrf_id, (name) ? name : "(NULL)"); - if (name) - { - strncpy (vrf->name, name, namelen); - vrf->name[namelen] = '\0'; - listnode_add_sort (vrf_list, vrf); - } - - if ((vrf_id != VRF_UNKNOWN) && (rn != NULL)) - { - rn->info = vrf; - vrf->node = rn; - } - vrf->vrf_id = vrf_id; - - /* Initialize interfaces. */ + strcpy (vrf->name, name); + listnode_add_sort (vrf_list, vrf); if_init (&vrf->iflist); - } + if (vrf_master.vrf_new_hook) + { + (*vrf_master.vrf_new_hook) (vrf_id, name, &vrf->info); - if (vrf_master.vrf_new_hook && name) + if (debug_vrf && vrf->info) + zlog_info ("zvrf is created."); + } + if (debug_vrf) + zlog_debug("Vrf Created: %p", vrf); + return vrf; + } + /* + * Valid vrf name and valid vrf_id case + * + * This can be passed from the kernel + */ + else if (name && vrf_id != VRF_UNKNOWN) { - (*vrf_master.vrf_new_hook) (vrf_id, name, &vrf->info); + vrf = vrf_list_lookup_by_name (name); + if (vrf) + { + /* + * If the passed in vrf_id and name match + * return, nothing to do here. + */ + if (vrf->vrf_id == vrf_id) + return vrf; - if (vrf->info) - zlog_info ("zvrf is created."); + /* + * Now we have a situation where we've had a + * vrf created, but not yet created the vrf_id route + * node, let's do so and match the code up. + */ + vrf_build_key (vrf_id, &p); + rn = route_node_get (vrf_table, &p); + + rn->info = vrf; + vrf->node = rn; + vrf->vrf_id = vrf_id; + if (vrf_master.vrf_new_hook) + (*vrf_master.vrf_new_hook) (vrf_id, name, &vrf->info); + + if (debug_vrf) + zlog_debug("Vrf found matched stuff up: %p", vrf); + + return vrf; + } + else + { + /* + * We can have 1 of two situations here + * We've already been told about the vrf_id + * or we haven't. + */ + vrf_build_key (vrf_id, &p); + rn = route_node_get (vrf_table, &p); + if (rn->info) + { + vrf = rn->info; + route_unlock_node (rn); + /* + * We know at this point that the vrf->name is not + * right because we would have caught it above. + * so let's set it. + */ + strcpy (vrf->name, name); + listnode_add_sort (vrf_list, vrf); + if (vrf_master.vrf_new_hook) + { + (*vrf_master.vrf_new_hook) (vrf_id, name, &vrf->info); + + if (debug_vrf && vrf->info) + zlog_info ("zvrf is created."); + } + if (debug_vrf) + zlog_debug("Vrf Created: %p", vrf); + return vrf; + } + else + { + vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf)); + + rn->info = vrf; + vrf->node = rn; + vrf->vrf_id = vrf_id; + strcpy (vrf->name, name); + listnode_add_sort (vrf_list, vrf); + if_init (&vrf->iflist); + if (vrf_master.vrf_new_hook) + { + (*vrf_master.vrf_new_hook) (vrf_id, name, &vrf->info); + + if (debug_vrf && vrf->info) + zlog_info ("zvrf is created."); + } + if (debug_vrf) + zlog_debug("Vrf Created: %p", vrf); + return vrf; + } + } + } + /* + * The final case, we've been passed a valid vrf_id + * but no name. So we create the route node + * if it hasn't already been created. + */ + else if (!name) + { + vrf_build_key (vrf_id, &p); + rn = route_node_get (vrf_table, &p); + zlog_debug("Vrf found: %p", rn->info); + + if (rn->info) + { + route_unlock_node (rn); + return (rn->info); + } + else + { + vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf)); + rn->info = vrf; + vrf->node = rn; + vrf->vrf_id = vrf_id; + if_init (&vrf->iflist); + if (debug_vrf) + zlog_debug("Vrf Created: %p", vrf); + return vrf; + } } - return vrf; + /* + * We shouldn't get here and if we do + * something has gone wrong. + */ + return NULL; } /* Delete a VRF. This is called in vrf_terminate(). */ diff --git a/tools/quagga-reload.py b/tools/quagga-reload.py index f67a6ce94a..45f579c4e3 100755 --- a/tools/quagga-reload.py +++ b/tools/quagga-reload.py @@ -439,47 +439,107 @@ def line_exist(lines, target_ctx_keys, target_line): return False -def ignore_bgp_swpx_peergroup(lines_to_add, lines_to_del): - ''' - BGP changed how it displays swpX peers that are part of peer-group. Older - versions of quagga would display these on separate lines: - neighbor swp1 interface - neighbor swp1 peer-group FOO - - but today we display via a single line - neighbor swp1 interface peer-group FOO - - This change confuses quagga-reload.py so check to see if we are deleting - neighbor swp1 interface peer-group FOO - - and adding - neighbor swp1 interface - neighbor swp1 peer-group FOO - - If so then chop the del line and the corresponding add lines - ''' +def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # Quite possibly the most confusing (while accurate) variable names in history lines_to_add_to_del = [] lines_to_del_to_del = [] for (ctx_keys, line) in lines_to_del: + deleted = False + if ctx_keys[0].startswith('router bgp') and line.startswith('neighbor '): + """ + BGP changed how it displays swpX peers that are part of peer-group. Older + versions of quagga would display these on separate lines: + neighbor swp1 interface + neighbor swp1 peer-group FOO + + but today we display via a single line + neighbor swp1 interface peer-group FOO + + This change confuses quagga-reload.py so check to see if we are deleting + neighbor swp1 interface peer-group FOO + + and adding + neighbor swp1 interface + neighbor swp1 peer-group FOO + + If so then chop the del line and the corresponding add lines + """ + re_swpx_int_peergroup = re.search('neighbor (\S+) interface peer-group (\S+)', line) + re_swpx_int_v6only_peergroup = re.search('neighbor (\S+) interface v6only peer-group (\S+)', line) + + if re_swpx_int_peergroup or re_swpx_int_v6only_peergroup: + swpx_interface = None + swpx_peergroup = None + + if re_swpx_int_peergroup: + swpx = re_swpx_int_peergroup.group(1) + peergroup = re_swpx_int_peergroup.group(2) + swpx_interface = "neighbor %s interface" % swpx + elif re_swpx_int_v6only_peergroup: + swpx = re_swpx_int_v6only_peergroup.group(1) + peergroup = re_swpx_int_v6only_peergroup.group(2) + swpx_interface = "neighbor %s interface v6only" % swpx - if re_swpx_int_peergroup: - swpx = re_swpx_int_peergroup.group(1) - peergroup = re_swpx_int_peergroup.group(2) - swpx_interface = "neighbor %s interface" % swpx swpx_peergroup = "neighbor %s peer-group %s" % (swpx, peergroup) - found_add_swpx_interface = line_exist(lines_to_add, ctx_keys, swpx_interface) found_add_swpx_peergroup = line_exist(lines_to_add, ctx_keys, swpx_peergroup) + tmp_ctx_keys = list(ctx_keys) + + if not found_add_swpx_peergroup: + tmp_ctx_keys = list(ctx_keys) + tmp_ctx_keys.append('address-family ipv4 unicast') + tmp_ctx_keys = tuple(tmp_ctx_keys) + found_add_swpx_peergroup = line_exist(lines_to_add, tmp_ctx_keys, swpx_peergroup) + + if not found_add_swpx_peergroup: + tmp_ctx_keys = list(ctx_keys) + tmp_ctx_keys.append('address-family ipv6 unicast') + tmp_ctx_keys = tuple(tmp_ctx_keys) + found_add_swpx_peergroup = line_exist(lines_to_add, tmp_ctx_keys, swpx_peergroup) if found_add_swpx_interface and found_add_swpx_peergroup: + deleted = True lines_to_del_to_del.append((ctx_keys, line)) lines_to_add_to_del.append((ctx_keys, swpx_interface)) - lines_to_add_to_del.append((ctx_keys, swpx_peergroup)) + lines_to_add_to_del.append((tmp_ctx_keys, swpx_peergroup)) + + if not deleted: + found_add_line = line_exist(lines_to_add, ctx_keys, line) + + if found_add_line: + lines_to_del_to_del.append((ctx_keys, line)) + lines_to_add_to_del.append((ctx_keys, line)) + else: + ''' + We have commands that used to be displayed in the global part + of 'router bgp' that are now displayed under 'address-family ipv4 unicast' + + # old way + router bgp 64900 + neighbor ISL advertisement-interval 0 + + vs. + + # new way + router bgp 64900 + address-family ipv4 unicast + neighbor ISL advertisement-interval 0 + + Look to see if we are deleting it in one format just to add it back in the other + ''' + if ctx_keys[0].startswith('router bgp') and len(ctx_keys) > 1 and ctx_keys[1] == 'address-family ipv4 unicast': + tmp_ctx_keys = list(ctx_keys)[:-1] + tmp_ctx_keys = tuple(tmp_ctx_keys) + + found_add_line = line_exist(lines_to_add, tmp_ctx_keys, line) + + if found_add_line: + lines_to_del_to_del.append((ctx_keys, line)) + lines_to_add_to_del.append((tmp_ctx_keys, line)) for (ctx_keys, line) in lines_to_del_to_del: lines_to_del.remove((ctx_keys, line)) @@ -548,7 +608,7 @@ def compare_context_objects(newconf, running): for line in newconf_ctx.lines: lines_to_add.append((newconf_ctx_keys, line)) - (lines_to_add, lines_to_del) = ignore_bgp_swpx_peergroup(lines_to_add, lines_to_del) + (lines_to_add, lines_to_del) = ignore_delete_re_add_lines(lines_to_add, lines_to_del) return (lines_to_add, lines_to_del, restart_bgpd) diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 5624435f88..0eba902112 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -88,6 +88,9 @@ zebra_vrf_new (vrf_id_t vrf_id, const char *name, void **info) router_id_init (zvrf); } + if (zvrf->vrf_id == VRF_UNKNOWN) + zvrf->vrf_id = vrf_id; + return 0; }