diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 3ea74f2bdb..7626077c95 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -234,9 +234,6 @@ bgp_exit (int status) if (retain_mode) if_add_hook (IF_DELETE_HOOK, NULL); - /* free interface and connected route information. */ - bgp_if_finish (); - /* reverse bgp_master_init */ for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) bgp_delete (bgp); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index a7d2f7f928..38cabed3d5 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3058,6 +3058,9 @@ bgp_delete (struct bgp *bgp) if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) bgp_zebra_instance_deregister (bgp); + /* Free interfaces in this instance. */ + bgp_if_finish (bgp); + /* If Default instance or VRF, unlink from the VRF structure. */ vrf = bgp_vrf_lookup_by_instance_type (bgp); if (vrf) @@ -7158,34 +7161,27 @@ bgp_master_init (void) } /* - * Free up connected routes and interfaces; invoked upon bgp_exit() + * Free up connected routes and interfaces for a BGP instance. Invoked upon + * instance delete (non-default only) or BGP exit. */ void -bgp_if_finish (void) +bgp_if_finish (struct bgp *bgp) { - struct bgp *bgp; - struct listnode *node, *nnode; - - for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) - { - struct listnode *ifnode, *ifnnode; - struct interface *ifp; + struct listnode *ifnode, *ifnnode; + struct interface *ifp; - if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW) - continue; + if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW) + return; - for (ALL_LIST_ELEMENTS (vrf_iflist(bgp->vrf_id), ifnode, ifnnode, ifp)) - { - struct listnode *c_node, *c_nnode; - struct connected *c; + for (ALL_LIST_ELEMENTS (vrf_iflist(bgp->vrf_id), ifnode, ifnnode, ifp)) + { + struct listnode *c_node, *c_nnode; + struct connected *c; - for (ALL_LIST_ELEMENTS (ifp->connected, c_node, c_nnode, c)) - bgp_connected_delete (bgp, c); - - if_delete (ifp); - } - list_free (vrf_iflist(bgp->vrf_id)); + for (ALL_LIST_ELEMENTS (ifp->connected, c_node, c_nnode, c)) + bgp_connected_delete (bgp, c); } + vrf_iflist_terminate (bgp->vrf_id); } void diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 8c6addacb3..04f5f09586 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1174,7 +1174,7 @@ extern char *peer_uptime (time_t, char *, size_t, u_char, json_object *); extern int bgp_config_write (struct vty *); extern void bgp_config_write_family_header (struct vty *, afi_t, safi_t, int *); -extern void bgp_if_finish (void); +extern void bgp_if_finish (struct bgp *); extern void bgp_master_init (void); extern void bgp_init (void); diff --git a/debian/bgpd.service b/debian/bgpd.service index c7dc9418f3..3162df1a4a 100644 --- a/debian/bgpd.service +++ b/debian/bgpd.service @@ -17,5 +17,6 @@ Restart=on-abnormal LimitNOFILE=1024 ExecStart=/usr/lib/quagga/bgpd $BGPD_OPTIONS ExecStartPost=/usr/bin/vtysh -b -n +ExecStopPost=/usr/bin/touch /var/run/quagga/bgpd.was_running [Install] WantedBy=network-online.target diff --git a/debian/isisd.service b/debian/isisd.service index ba2ca68212..888aaa0620 100644 --- a/debian/isisd.service +++ b/debian/isisd.service @@ -17,5 +17,6 @@ Restart=on-abnormal LimitNOFILE=1024 ExecStart=/usr/lib/quagga/isisd $ISISD_OPTIONS ExecStartPost=/usr/bin/vtysh -b -n +ExecStopPost=/bin/touch /var/run/quagga/isisd.was_running [Install] WantedBy=network-online.target diff --git a/debian/ospf6d.service b/debian/ospf6d.service index 2dee461acf..31a9cd4777 100644 --- a/debian/ospf6d.service +++ b/debian/ospf6d.service @@ -16,5 +16,6 @@ RestartSec=5 Restart=on-abnormal ExecStart=/usr/lib/quagga/ospf6d $OSPF6D_OPTIONS ExecStartPost=/usr/bin/vtysh -b -n +ExecStopPost=/usr/bin/touch /var/run/quagga/ospf6d.was_running [Install] WantedBy=network-online.target diff --git a/debian/ospfd.service b/debian/ospfd.service index 907d546d76..92c310f642 100644 --- a/debian/ospfd.service +++ b/debian/ospfd.service @@ -17,5 +17,6 @@ Restart=on-abnormal LimitNOFILE=1024 ExecStart=/usr/lib/quagga/ospfd $OSPFD_OPTIONS ExecStartPost=/usr/bin/vtysh -b -n +ExecStopPost=/usr/bin/touch /var/run/quagga/ospfd.was_running [Install] WantedBy=network-online.target diff --git a/debian/ospfd@.service b/debian/ospfd@.service index 2cdaea8642..eb3fe9c1d9 100644 --- a/debian/ospfd@.service +++ b/debian/ospfd@.service @@ -17,5 +17,6 @@ Restart=on-abnormal LimitNOFILE=1024 ExecStart=/usr/lib/quagga/ospfd $OSPFD_OPTIONS -n %I ExecStartPost=/usr/bin/vtysh -b -n +ExecStopPost=/bin/touch /var/run/quagga/ospfd.%I.was_running [Install] WantedBy=network-online.target diff --git a/debian/quagga.install b/debian/quagga.install index 7d50178e34..0c3db58ffa 100644 --- a/debian/quagga.install +++ b/debian/quagga.install @@ -3,6 +3,7 @@ usr/bin/vtysh usr/include/quagga/ usr/lib/ tools/quagga-reload.py usr/lib/quagga/ +tools/startup usr/lib/quagga/ usr/share/doc/quagga/ usr/share/man/man1/vtysh.1 usr/share/man/man8 diff --git a/debian/quagga.service b/debian/quagga.service index 0113819f5f..f052740b8f 100644 --- a/debian/quagga.service +++ b/debian/quagga.service @@ -8,13 +8,13 @@ Type=simple RemainAfterExit=yes TimeoutSec=2m30s TimeoutStopSec=1m -ExecStartPre=-/bin/systemctl start zebra.service -ExecStartPre=-/bin/systemctl start bgpd.service -ExecStartPre=-/bin/systemctl start isisd.service -ExecStartPre=-/bin/systemctl start ospfd.service -ExecStartPre=-/bin/systemctl start ospf6d.service -ExecStartPre=-/bin/systemctl start ripd.service -ExecStartPre=-/bin/systemctl start ripngd.service +ExecStartPre=-/usr/lib/quagga/startup zebra +ExecStartPre=-/usr/lib/quagga/startup bgpd +ExecStartPre=-/usr/lib/quagga/startup isisd +ExecStartPre=-/usr/lib/quagga/startup ospfd +ExecStartPre=-/usr/lib/quagga/startup ospf6d +ExecStartPre=-/usr/lib/quagga/startup ripd +ExecStartPre=-/usr/lib/quagga/startup ripngd ExecStartPost=-/usr/bin/vtysh -b -n # ExecReload=/usr/lib/quagga/quagga-reload.py --reload /etc/quagga/Quagga.conf diff --git a/debian/ripd.service b/debian/ripd.service index 661b83b5c2..f322d8db5f 100644 --- a/debian/ripd.service +++ b/debian/ripd.service @@ -17,5 +17,6 @@ Restart=on-abnormal LimitNOFILE=1024 ExecStart=/usr/lib/quagga/ripd $RIPD_OPTIONS ExecStartPost=/usr/bin/vtysh -b -n +ExecStopPost=/usr/bin/touch /var/run/quagga/ripd.was_running [Install] WantedBy=network-online.target diff --git a/debian/ripngd.service b/debian/ripngd.service index cd39feeb8d..8c406e972b 100644 --- a/debian/ripngd.service +++ b/debian/ripngd.service @@ -17,5 +17,6 @@ Restart=on-abnormal LimitNOFILE=1024 ExecStart=/usr/lib/quagga/ripngd $RIPNGD_OPTIONS ExecStartPost=/usr/bin/vtysh -b -n +ExecStopPost=/bin/touch /var/run/quagga/ripngd.was_running [Install] WantedBy=network-online.target diff --git a/debian/zebra.service b/debian/zebra.service index e540e49330..281a162d2d 100644 --- a/debian/zebra.service +++ b/debian/zebra.service @@ -16,5 +16,6 @@ Restart=on-abnormal LimitNOFILE=1024 ExecStart=/usr/lib/quagga/zebra $ZEBRA_OPTIONS ExecStartPost=/usr/bin/vtysh -b -n +ExecStopPost=/usr/bin/touch /var/run/quagga/zebra.was_running [Install] WantedBy=network-online.target diff --git a/lib/vrf.c b/lib/vrf.c index 45cc8735a2..a4cddeefb4 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -495,6 +495,15 @@ vrf_iflist_get (vrf_id_t vrf_id) return vrf->iflist; } +/* Free the interface list of the specified VRF. */ +void +vrf_iflist_terminate (vrf_id_t vrf_id) +{ + struct vrf * vrf = vrf_lookup (vrf_id); + if (vrf && vrf->iflist) + if_terminate (vrf->vrf_id, &vrf->iflist); +} + /* * VRF bit-map */ diff --git a/lib/vrf.h b/lib/vrf.h index 3ef2979dc1..9f3b231735 100644 --- a/lib/vrf.h +++ b/lib/vrf.h @@ -180,6 +180,8 @@ extern void *vrf_info_lookup (vrf_id_t); extern struct list *vrf_iflist (vrf_id_t); /* Get the interface list of the specified VRF. Create one if not find. */ extern struct list *vrf_iflist_get (vrf_id_t); +/* Free the interface list of the specified VRF. */ +extern void vrf_iflist_terminate (vrf_id_t vrf_id); /* * VRF bit-map: maintaining flags, one bit per VRF ID diff --git a/tools/startup b/tools/startup new file mode 100755 index 0000000000..7ebb5116a1 --- /dev/null +++ b/tools/startup @@ -0,0 +1,20 @@ +#!/bin/bash +# Script to see if we should startup the particular +# daemon as part of systemd initialization +# If the daemon was running (set by the ExecStopPost +# action in the Unit file ) or if the daemon +# is enabled start it up +FILE="/var/run/quagga/$1.was_running" +if [ -e $FILE ] +then + rm $FILE + systemctl start $1 +fi + +systemctl is-enabled $1 > /dev/null +if [ $? -eq 0 ] +then + systemctl start $1 +fi + +exit 0 diff --git a/zebra/interface.c b/zebra/interface.c index 8b25c33f17..7b19379910 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -183,6 +183,14 @@ if_lookup_by_index_per_ns (struct zebra_ns *ns, u_int32_t ifindex) return ifp; } +const char * +ifindex2ifname_per_ns (struct zebra_ns *zns, unsigned int ifindex) +{ + struct interface *ifp; + + return ((ifp = if_lookup_by_index_per_ns (zns, ifindex)) != NULL) ? + ifp->name : "unknown"; +} /* Tie an interface address to its derived subnet list of addresses. */ int diff --git a/zebra/interface.h b/zebra/interface.h index ab018596c0..3d8a82d454 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -210,6 +210,8 @@ struct zebra_if extern struct interface *if_lookup_by_index_per_ns (struct zebra_ns *, u_int32_t); extern struct interface *if_link_per_ns (struct zebra_ns *, struct interface *); +extern const char *ifindex2ifname_per_ns (struct zebra_ns *, unsigned int); + extern void if_unlink_per_ns (struct interface *); extern void if_nbr_ipv6ll_to_ipv4ll_neigh_update (struct interface *ifp, struct in6_addr *address, int add); diff --git a/zebra/rib.h b/zebra/rib.h index 84941a6737..ae1f923cde 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -323,6 +323,10 @@ struct zebra_vrf /* FIB identifier. */ u_char fib_id; + /* Flags. */ + u_int16_t flags; +#define ZEBRA_VRF_RIB_SCHEDULED (1 << 0) + u_int32_t table_id; /* Routing table. */ diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index d3ee6005c1..77f274a943 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -545,7 +545,7 @@ netlink_vrf_change (struct nlmsghdr *h, struct rtattr *tb, const char *name) * TODO: Status changes will be handled against the VRF "interface". */ vrf = vrf_lookup ((vrf_id_t)ifi->ifi_index); - if (vrf) + if (vrf && vrf->info) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: RTM_NEWLINK status for VRF(%s) index %u - ignored", @@ -649,7 +649,7 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h, if (kind && strcmp(kind, "vrf") == 0) { netlink_vrf_change(h, tb[IFLA_LINKINFO], name); - return 0; + vrf_id = (vrf_id_t)ifi->ifi_index; } } @@ -1277,7 +1277,7 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h, if (kind && strcmp(kind, "vrf") == 0) { netlink_vrf_change(h, tb[IFLA_LINKINFO], name); - return 0; + vrf_id = (vrf_id_t)ifi->ifi_index; } } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5b10739b4c..39b9d452ca 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1656,10 +1656,25 @@ process_subq (struct list * subq, u_char qindex) static void meta_queue_process_complete (struct work_queue *dummy) { - zebra_evaluate_rnh(0, AF_INET, 0, RNH_NEXTHOP_TYPE, NULL); - zebra_evaluate_rnh(0, AF_INET, 0, RNH_IMPORT_CHECK_TYPE, NULL); - zebra_evaluate_rnh(0, AF_INET6, 0, RNH_NEXTHOP_TYPE, NULL); - zebra_evaluate_rnh(0, AF_INET6, 0, RNH_IMPORT_CHECK_TYPE, NULL); + vrf_iter_t iter; + struct zebra_vrf *zvrf; + + /* Evaluate nexthops for those VRFs which underwent route processing. This + * should limit the evaluation to the necessary VRFs in most common + * situations. + */ + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + { + if (((zvrf = vrf_iter2info (iter)) != NULL) && + (zvrf->flags & ZEBRA_VRF_RIB_SCHEDULED)) + { + zvrf->flags &= ~ZEBRA_VRF_RIB_SCHEDULED; + zebra_evaluate_rnh(zvrf->vrf_id, AF_INET, 0, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(zvrf->vrf_id, AF_INET, 0, RNH_IMPORT_CHECK_TYPE, NULL); + zebra_evaluate_rnh(zvrf->vrf_id, AF_INET6, 0, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(zvrf->vrf_id, AF_INET6, 0, RNH_IMPORT_CHECK_TYPE, NULL); + } + } } /* Dispatch the meta queue by picking, processing and unlocking the next RN from @@ -1714,6 +1729,7 @@ rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) RNODE_FOREACH_RIB (rn, rib) { u_char qindex = meta_queue_map[rib->type]; + struct zebra_vrf *zvrf; /* Invariant: at this point we always have rn->info set. */ if (CHECK_FLAG (rib_dest_from_rnode (rn)->flags, @@ -1728,6 +1744,10 @@ rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug ("%u:%s/%d: rn %p queued into sub-queue %u", rib->vrf_id, buf, rn->p.prefixlen, rn, qindex); + + zvrf = zebra_vrf_lookup (rib->vrf_id); + if (zvrf) + zvrf->flags |= ZEBRA_VRF_RIB_SCHEDULED; } } diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 897067fd4b..74e63d9467 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -44,6 +44,7 @@ #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/zebra_rnh.h" +#include "zebra/interface.h" /* Default rtm_table for all clients */ extern struct zebra_t zebrad; @@ -946,18 +947,18 @@ print_nh (struct nexthop *nexthop, struct vty *vty) case NEXTHOP_TYPE_IPV4_IFINDEX: vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4)); if (nexthop->ifindex) - vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex)); + vty_out (vty, ", %s", ifindex2ifname_per_ns (dzns, nexthop->ifindex)); break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: vty_out (vty, " %s", inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); if (nexthop->ifindex) - vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex)); + vty_out (vty, ", via %s", ifindex2ifname_per_ns (dzns, nexthop->ifindex)); break; case NEXTHOP_TYPE_IFINDEX: vty_out (vty, " is directly connected, %s", - ifindex2ifname (nexthop->ifindex)); + ifindex2ifname_per_ns (dzns, nexthop->ifindex)); break; case NEXTHOP_TYPE_BLACKHOLE: vty_out (vty, " is directly connected, Null0");