ospfd: Impl. per interface 'ip ospf area' command

Use with interface command:
 interface ppp0
 ip ospf area 0.0.0.0
This will enable OSPF on ppp0 with area 0.0.0.0

Remove with "no ip ospf area"

* ospf_vty.c: add "ip ospf area (A.B.C.D|<0-4294967295>)" interface command

* ospfd.c: (ospf_interface_{un,}set) new helper function to enable/disable
  OSPF on a specific interface.
  (ospf_if_update) 2 possible paths now to deal with interface updates.

Acked-by: Donald Sharp <sharpd@cumulusnetworks.com>
diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h
index ed698c8..a437bfb 100644
--- a/ospfd/ospf_interface.h
+++ b/ospfd/ospf_interface.h
@@ -47,6 +47,7 @@
   DECLARE_IF_PARAM (u_int32_t, retransmit_interval); /* Retransmission Interval */
   DECLARE_IF_PARAM (u_char, passive_interface);      /* OSPF Interface is passive: no sending or receiving (no need to join multicast groups) */
   DECLARE_IF_PARAM (u_char, priority);               /* OSPF Interface priority */
+  DECLARE_IF_PARAM (struct in_addr, if_area);        /* Enable OSPF on this interface with area if_area */
   DECLARE_IF_PARAM (u_char, type);                   /* type of interface */
 #define OSPF_IF_ACTIVE                  0
 #define OSPF_IF_PASSIVE		        1
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index c6f3b40..dd4d312 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -5883,6 +5883,70 @@
        "OSPF interface commands\n"
        "Link state transmit delay\n")
 
+DEFUN (ip_ospf_area,
+       ip_ospf_area_cmd,
+       "ip ospf area (A.B.C.D|<0-4294967295>)",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Enable OSPF on this interface\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n")
+{
+  struct interface *ifp = vty->index;
+  int format, ret;
+  struct in_addr area_id;
+  struct ospf *ospf;
+  struct ospf_if_params *params;
+
+  ret = ospf_str2area_id (argv[0], &area_id, &format);
+
+  if (ret < 0)
+    {
+      vty_out (vty, "Please specify area by A.B.C.D|<0-4294967295>%s",
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  params = IF_DEF_PARAMS (ifp);
+  if (OSPF_IF_PARAM_CONFIGURED(params, if_area))
+    {
+      vty_out (vty, "There is already a interface statement.%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  if (memcmp (ifp->name, "VLINK", 5) == 0)
+    {
+      vty_out (vty, "Cannot enable OSPF on a virtual link.%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  SET_IF_PARAM (params, if_area);
+  params->if_area = area_id;
+  ospf_interface_set (ifp);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_ospf_area,
+       no_ip_ospf_area_cmd,
+       "no ip ospf area",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Disable OSPF on this interface\n")
+{
+  struct interface *ifp = vty->index;
+  struct ospf *ospf;
+  struct ospf_if_params *params;
+
+  params = IF_DEF_PARAMS (ifp);
+  if (!OSPF_IF_PARAM_CONFIGURED(params, if_area))
+    return CMD_SUCCESS;
+
+  UNSET_IF_PARAM (params, if_area);
+
+  ospf_interface_unset (ifp);
+  return CMD_SUCCESS;
+}
+
 DEFUN (ospf_redistribute_source,
        ospf_redistribute_source_cmd,
        "redistribute " QUAGGA_REDIST_STR_OSPFD
@@ -6947,6 +7011,14 @@
 	    vty_out (vty, "%s", VTY_NEWLINE);
 	  }
 
+	/* Area  print. */
+	if (OSPF_IF_PARAM_CONFIGURED (params, if_area))
+	  {
+	    vty_out (vty, " ip ospf area %s%s",
+		     inet_ntoa (params->if_area),
+		     VTY_NEWLINE);
+	  }
+
     /* MTU ignore print. */
     if (OSPF_IF_PARAM_CONFIGURED (params, mtu_ignore) &&
        params->mtu_ignore != OSPF_MTU_IGNORE_DEFAULT)
@@ -7597,6 +7669,10 @@
   install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd);
   install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_cmd);
 
+  /* "ip ospf area" commands. */
+  install_element (INTERFACE_NODE, &ip_ospf_area_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_area_cmd);
+
   /* These commands are compatibitliy for previous version. */
   install_element (INTERFACE_NODE, &ospf_authentication_key_cmd);
   install_element (INTERFACE_NODE, &no_ospf_authentication_key_cmd);
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index c8ad25f..f6669d7 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -871,12 +871,17 @@
   /* Find interfaces that not configured already.  */
   for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi))
     {
+      struct ospf_if_params *params;
       int found = 0;
       struct connected *co = oi->connected;
       
       if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
         continue;
       
+      params = IF_DEF_PARAMS (oi->ifp);
+      if (OSPF_IF_PARAM_CONFIGURED(params, if_area))
+        continue;
+      
       for (rn = route_top (ospf->networks); rn; rn = route_next (rn))
         {
           if (rn->info == NULL)
@@ -902,6 +907,97 @@
   return 1;
 }
 
+int
+ospf_interface_set (struct interface *ifp)
+{
+  struct ospf_area *area;
+  struct listnode *cnode;
+  struct connected *co;
+  struct ospf *ospf;
+  struct ospf_if_params *params;
+  struct in_addr area_id;
+  int ret = OSPF_AREA_ID_FORMAT_ADDRESS;
+
+  if ((ospf = ospf_lookup ()) == NULL)
+      return 1; /* Ospf not ready yet */
+
+  params = IF_DEF_PARAMS (ifp);
+  area_id = params->if_area;
+
+  area = ospf_area_get (ospf, area_id, ret);
+ 
+  for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, co))
+    {
+      struct ospf_interface *oi;
+
+      if (CHECK_FLAG(co->flags,ZEBRA_IFA_SECONDARY))
+	continue;
+
+      oi = ospf_if_table_lookup(ifp, co->address);
+      if (oi) 
+	{ /* Just adjust area for existing interface */
+	  ospf_area_del_if (oi->area, oi);
+	  oi->area = area;
+	  ospf_area_add_if (oi->area, oi);
+	}
+      else
+	{
+	  add_ospf_interface(ifp, area, co);
+	}
+    }
+
+  /* Update connected redistribute. */
+  update_redistributed(ospf, 1); /* interface possibly added */
+  ospf_area_check_free (ospf, area_id);
+
+  return 1;
+}
+
+int
+ospf_interface_unset (struct interface *ifp)
+{
+  struct route_node *rn_oi, *rn;
+  struct ospf *ospf;
+
+  if ((ospf = ospf_lookup ()) == NULL)
+    return 1; /* Ospf not ready yet */
+
+  /* Find interfaces that may need to be removed. */
+  for (rn_oi = route_top (IF_OIFS (ifp)); rn_oi; rn_oi = route_next (rn_oi))
+    {
+      struct ospf_interface *oi;
+      struct connected *co;
+      int found = 0;
+
+      if ( (oi = rn_oi->info) == NULL)
+	continue;
+      if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+	continue;
+      co = oi->connected;
+
+      for (rn = route_top (ospf->networks); rn; rn = route_next (rn))
+	{
+	  if (rn->info == NULL)
+	    continue;
+
+	  if (ospf_network_match_iface(co,&rn->p))
+	    {
+	      found = 1;
+	      route_unlock_node (rn);
+	      break;
+	    }
+	}
+
+      if (found == 0)
+	ospf_if_free (oi);
+    }
+
+  /* Update connected redistribute. */
+  update_redistributed(ospf, 0); /* interfaces possibly removed */
+   return 1;
+ }
+
+
 /* Check whether interface matches given network
  * returns: 1, true. 0, false
  */
@@ -994,15 +1090,20 @@
   /* OSPF must be on and Router-ID must be configured. */
   if (!ospf || ospf->router_id.s_addr == 0)
     return;
-
-  /* Run each netowrk for this interface. */
-  for (rn = route_top (ospf->networks); rn; rn = route_next (rn))
-    if (rn->info != NULL)
-      {
-        network = (struct ospf_network *) rn->info;
-        area = ospf_area_get (ospf, network->area_id, network->format);
-        ospf_network_run_interface (&rn->p, area, ifp);
-      }
+  
+  if (OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS (ifp), if_area))
+    ospf_interface_set (ifp);
+  else
+    {
+      /* Run each netowrk for this interface. */
+      for (rn = route_top (ospf->networks); rn; rn = route_next (rn))
+	if (rn->info != NULL)
+	  {
+	    network = (struct ospf_network *) rn->info;
+	    area = ospf_area_get (ospf, network->area_id, network->format);
+	    ospf_network_run_interface (&rn->p, area, ifp);
+	  }
+    }
 }
 
 void