]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/interface.c
zebra: add northbound support for zebra interface
[mirror_frr.git] / zebra / interface.c
index 59cbfc6854559cf6a4b99841ff94fade1339b5f7..7c0bddfadd67926484ee1decbae82aef4d80ee88 100644 (file)
@@ -500,7 +500,7 @@ void if_flags_update(struct interface *ifp, uint64_t newflags)
 
 /* Wake up configured address if it is not in current kernel
    address. */
-static void if_addr_wakeup(struct interface *ifp)
+void if_addr_wakeup(struct interface *ifp)
 {
        struct listnode *node, *nnode;
        struct connected *ifc;
@@ -1881,6 +1881,24 @@ DEFUN (show_interface_desc_vrf_all,
        return CMD_SUCCESS;
 }
 
+int if_multicast_set(struct interface *ifp)
+{
+       struct zebra_if *if_data;
+
+       if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
+               if (if_set_flags(ifp, IFF_MULTICAST) < 0) {
+                       zlog_debug("Can't set multicast flag on interface %s",
+                                  ifp->name);
+                       return -1;
+               }
+               if_refresh(ifp);
+       }
+       if_data = ifp->info;
+       if_data->multicast = IF_ZEBRA_MULTICAST_ON;
+
+       return 0;
+}
+
 DEFUN (multicast,
        multicast_cmd,
        "multicast",
@@ -1904,6 +1922,24 @@ DEFUN (multicast,
        return CMD_SUCCESS;
 }
 
+int if_multicast_unset(struct interface *ifp)
+{
+       struct zebra_if *if_data;
+
+       if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
+               if (if_unset_flags(ifp, IFF_MULTICAST) < 0) {
+                       zlog_debug("Can't unset multicast flag on interface %s",
+                                  ifp->name);
+                       return -1;
+               }
+               if_refresh(ifp);
+       }
+       if_data = ifp->info;
+       if_data->multicast = IF_ZEBRA_MULTICAST_OFF;
+
+       return 0;
+}
+
 DEFUN (no_multicast,
        no_multicast_cmd,
        "no multicast",
@@ -1928,23 +1964,35 @@ DEFUN (no_multicast,
        return CMD_SUCCESS;
 }
 
-DEFUN (linkdetect,
-       linkdetect_cmd,
-       "link-detect",
-       "Enable link detection on interface\n")
+int if_linkdetect(struct interface *ifp, bool detect)
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
        int if_was_operative;
 
        if_was_operative = if_is_no_ptm_operative(ifp);
-       SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
+       if (detect) {
+               SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
 
-       /* When linkdetection is enabled, if might come down */
-       if (!if_is_no_ptm_operative(ifp) && if_was_operative)
-               if_down(ifp);
+               /* When linkdetection is enabled, if might come down */
+               if (!if_is_no_ptm_operative(ifp) && if_was_operative)
+                       if_down(ifp);
+       } else {
+               UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
 
+               /* Interface may come up after disabling link detection */
+               if (if_is_operative(ifp) && !if_was_operative)
+                       if_up(ifp);
+       }
        /* FIXME: Will defer status change forwarding if interface
           does not come down! */
+       return 0;
+}
+
+DEFUN(linkdetect, linkdetect_cmd, "link-detect",
+      "Enable link detection on interface\n")
+{
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+
+       if_linkdetect(ifp, true);
 
        return CMD_SUCCESS;
 }
@@ -1957,18 +2005,29 @@ DEFUN (no_linkdetect,
        "Disable link detection on interface\n")
 {
        VTY_DECLVAR_CONTEXT(interface, ifp);
-       int if_was_operative;
 
-       if_was_operative = if_is_no_ptm_operative(ifp);
-       UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
+       if_linkdetect(ifp, false);
+
+       return CMD_SUCCESS;
+}
 
-       /* Interface may come up after disabling link detection */
-       if (if_is_operative(ifp) && !if_was_operative)
-               if_up(ifp);
+int if_shutdown(struct interface *ifp)
+{
+       struct zebra_if *if_data;
 
-       /* FIXME: see linkdetect_cmd */
+       if (ifp->ifindex != IFINDEX_INTERNAL) {
+               /* send RA lifetime of 0 before stopping. rfc4861/6.2.5 */
+               rtadv_stop_ra(ifp);
+               if (if_unset_flags(ifp, IFF_UP) < 0) {
+                       zlog_debug("Can't shutdown interface %s", ifp->name);
+                       return -1;
+               }
+               if_refresh(ifp);
+       }
+       if_data = ifp->info;
+       if_data->shutdown = IF_ZEBRA_SHUTDOWN_ON;
 
-       return CMD_SUCCESS;
+       return 0;
 }
 
 DEFUN (shutdown_if,
@@ -1996,6 +2055,30 @@ DEFUN (shutdown_if,
        return CMD_SUCCESS;
 }
 
+int if_no_shutdown(struct interface *ifp)
+{
+       struct zebra_if *if_data;
+
+       if (ifp->ifindex != IFINDEX_INTERNAL) {
+               if (if_set_flags(ifp, IFF_UP | IFF_RUNNING) < 0) {
+                       zlog_debug("Can't up interface %s", ifp->name);
+                       return -1;
+               }
+               if_refresh(ifp);
+
+               /* Some addresses (in particular, IPv6 addresses on Linux) get
+                * removed when the interface goes down. They need to be
+                * readded.
+                */
+               if_addr_wakeup(ifp);
+       }
+
+       if_data = ifp->info;
+       if_data->shutdown = IF_ZEBRA_SHUTDOWN_OFF;
+
+       return 0;
+}
+
 DEFUN (no_shutdown_if,
        no_shutdown_if_cmd,
        "no shutdown",
@@ -2748,6 +2831,79 @@ DEFUN (no_link_params_use_bw,
        return CMD_SUCCESS;
 }
 
+int if_ip_address_install(struct interface *ifp, struct prefix *prefix,
+                         const char *label, struct prefix *pp)
+{
+       struct zebra_if *if_data;
+       struct prefix_ipv4 lp;
+       struct prefix_ipv4 *p;
+       struct connected *ifc;
+       enum zebra_dplane_result dplane_res;
+
+       if_data = ifp->info;
+
+       lp.family = prefix->family;
+       lp.prefix = prefix->u.prefix4;
+       lp.prefixlen = prefix->prefixlen;
+       apply_mask_ipv4(&lp);
+
+       ifc = connected_check_ptp(ifp, &lp, pp ? pp : NULL);
+       if (!ifc) {
+               ifc = connected_new();
+               ifc->ifp = ifp;
+
+               /* Address. */
+               p = prefix_ipv4_new();
+               *p = lp;
+               ifc->address = (struct prefix *)p;
+
+               if (pp) {
+                       SET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
+                       p = prefix_ipv4_new();
+                       *p = *(struct prefix_ipv4 *)pp;
+                       ifc->destination = (struct prefix *)p;
+               }
+
+               /* Label. */
+               if (label)
+                       ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label);
+
+               /* Add to linked list. */
+               listnode_add(ifp->connected, ifc);
+       }
+
+       /* This address is configured from zebra. */
+       if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED))
+               SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
+
+       /* In case of this route need to install kernel. */
+       if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED)
+           && CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)
+           && !(if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON)) {
+               /* Some system need to up the interface to set IP address. */
+               if (!if_is_up(ifp)) {
+                       if_set_flags(ifp, IFF_UP | IFF_RUNNING);
+                       if_refresh(ifp);
+               }
+
+               dplane_res = dplane_intf_addr_set(ifp, ifc);
+               if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) {
+                       zlog_debug(
+                               "dplane can't set interface IP address: %s.\n",
+                               dplane_res2str(dplane_res));
+                       return NB_ERR;
+               }
+
+               SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
+               /* The address will be advertised to zebra clients when the
+                * notification
+                * from the kernel has been received.
+                * It will also be added to the subnet chain list, then. */
+       }
+
+       return 0;
+}
+
 static int ip_address_install(struct vty *vty, struct interface *ifp,
                              const char *addr_str, const char *peer_str,
                              const char *label)
@@ -2842,6 +2998,51 @@ static int ip_address_install(struct vty *vty, struct interface *ifp,
        return CMD_SUCCESS;
 }
 
+int if_ip_address_uinstall(struct interface *ifp, struct prefix *prefix)
+{
+       struct connected *ifc = NULL;
+       enum zebra_dplane_result dplane_res;
+
+       if (prefix->family == AF_INET) {
+               /* Check current interface address. */
+               ifc = connected_check_ptp(ifp, prefix, NULL);
+               if (!ifc) {
+                       zlog_debug("interface %s Can't find address\n",
+                                  ifp->name);
+                       return -1;
+               }
+
+       } else if (prefix->family == AF_INET6) {
+               /* Check current interface address. */
+               ifc = connected_check(ifp, prefix);
+       }
+
+       if (!ifc) {
+               zlog_debug("interface %s Can't find address\n", ifp->name);
+               return -1;
+       }
+       UNSET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
+
+       /* This is not real address or interface is not active. */
+       if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED)
+           || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
+               listnode_delete(ifp->connected, ifc);
+               connected_free(&ifc);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       /* This is real route. */
+       dplane_res = dplane_intf_addr_unset(ifp, ifc);
+       if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) {
+               zlog_debug("Can't unset interface IP address: %s.\n",
+                          dplane_res2str(dplane_res));
+               return -1;
+       }
+       UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
+
+       return 0;
+}
+
 static int ip_address_uninstall(struct vty *vty, struct interface *ifp,
                                const char *addr_str, const char *peer_str,
                                const char *label)
@@ -2995,6 +3196,71 @@ DEFUN (no_ip_address_label,
 }
 #endif /* HAVE_NETLINK */
 
+int if_ipv6_address_install(struct interface *ifp, struct prefix *prefix,
+                           const char *label)
+{
+       struct zebra_if *if_data;
+       struct prefix_ipv6 cp;
+       struct connected *ifc;
+       struct prefix_ipv6 *p;
+       enum zebra_dplane_result dplane_res;
+
+       if_data = ifp->info;
+
+       cp.family = prefix->family;
+       cp.prefixlen = prefix->prefixlen;
+       cp.prefix = prefix->u.prefix6;
+       apply_mask_ipv6(&cp);
+
+       ifc = connected_check(ifp, (struct prefix *)&cp);
+       if (!ifc) {
+               ifc = connected_new();
+               ifc->ifp = ifp;
+
+               /* Address. */
+               p = prefix_ipv6_new();
+               *p = cp;
+               ifc->address = (struct prefix *)p;
+
+               /* Label. */
+               if (label)
+                       ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label);
+
+               /* Add to linked list. */
+               listnode_add(ifp->connected, ifc);
+       }
+
+       /* This address is configured from zebra. */
+       if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED))
+               SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
+
+       /* In case of this route need to install kernel. */
+       if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED)
+           && CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)
+           && !(if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON)) {
+               /* Some system need to up the interface to set IP address. */
+               if (!if_is_up(ifp)) {
+                       if_set_flags(ifp, IFF_UP | IFF_RUNNING);
+                       if_refresh(ifp);
+               }
+
+               dplane_res = dplane_intf_addr_set(ifp, ifc);
+               if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) {
+                       zlog_debug(
+                               "dplane can't set interface IP address: %s.\n",
+                               dplane_res2str(dplane_res));
+                       return NB_ERR;
+               }
+
+               SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
+               /* The address will be advertised to zebra clients when the
+                * notification
+                * from the kernel has been received. */
+       }
+
+       return 0;
+}
+
 static int ipv6_address_install(struct vty *vty, struct interface *ifp,
                                const char *addr_str, const char *peer_str,
                                const char *label)