route-manager_config.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * This code is provided as is by Juniper Networks SDK Developer Support.
00005  * It is provided with no warranties or guarantees, and Juniper Networks
00006  * will not provide support or maintenance of this code in any fashion.
00007  * The code is provided only to help a developer better understand how
00008  * the SDK can be used.
00009  * 
00010  * Copyright (c) 2010, Juniper Networks, Inc.
00011  * All rights reserved.
00012  */
00013 
00021 #include <stdbool.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <sys/types.h>
00025 #include <sys/queue.h>
00026 #include <sys/socket.h>
00027 #include <isc/eventlib.h>
00028 #include <arpa/inet.h>
00029 #include <jnx/trace.h>
00030 #include <jnx/junos_trace.h>
00031 #include <jnx/ssd_ipc_msg.h>
00032 #include <jnx/parse_ip.h>
00033 #include <ddl/ddl.h>
00034 #include <ddl/dax.h>
00035 #include "route-manager.h"
00036 
00037 #include OUT_H
00038 
00039 extern bool svc_ready;
00040 
00042 nh_t nh_pool[RM_NH_MAX];
00043 
00045 static LIST_HEAD(, route_s) rt_list;
00046 
00060 route_t *
00061 config_rt_get (in_addr_t addr, int prefix_len);
00062 route_t *
00063 config_rt_get (in_addr_t addr, int prefix_len)
00064 {
00065     route_t *rt;
00066 
00067     LIST_FOREACH(rt, &rt_list, entry) {
00068         if (rt->dst_addr.in.gin_addr == addr && rt->prefix_len == prefix_len) {
00069             return rt;
00070         }
00071     }
00072     return NULL;
00073 }
00074 
00085 static int
00086 config_nh_id_get (char *name)
00087 {
00088     int i;
00089     int free_id = 0;
00090 
00091     /* 0 can not be used as next-hop ID. */
00092     for (i = 1; i < RM_NH_MAX; i++) {
00093         if (nh_pool[i].op_state == NH_STATE_FREE) {
00094             free_id = i;
00095         }
00096         if (strncmp(nh_pool[i].name, name, sizeof(nh_pool[i].name)) == 0) {
00097             break;
00098         }
00099     }
00100     if (i == RM_NH_MAX) {
00101         /* No match. */
00102         if (free_id) {
00103             /* There is free next-hop, take it. */
00104             strncpy(nh_pool[free_id].name, name,
00105                     sizeof(nh_pool[free_id].name));
00106             nh_pool[free_id].op_state = NH_STATE_ADD_PENDING;
00107             return free_id;
00108         } else {
00109             /* No spare slot. */
00110             return -1;
00111         }
00112     } else {
00113         /* Find the match. */
00114         return i;
00115     }
00116 }
00117 
00134 static int
00135 config_rt_read (dax_walk_data_t *dwd, ddl_handle_t *dop, int action,
00136         void *data UNUSED)
00137 {
00138     const char *gateways_config[] = { "gateway", NULL };
00139     ddl_handle_t *dop_gws = NULL;
00140     ddl_handle_t *dop_gw = NULL;
00141     char buf[RM_NAME_SIZE];
00142     in_addr_t addr;
00143     int prefix_len;
00144     int af;
00145     int i;
00146     route_t *rt;
00147 
00148     switch (action) {
00149     case DAX_ITEM_DELETE_ALL:
00150         /* All items were deleted. */
00151         RM_TRACE(TF_CONFIG, "%s: Delete all routes.", __func__);
00152 
00153         /* Mark all routes delete-pending. */
00154         LIST_FOREACH (rt, &rt_list, entry) {
00155             rt->op_state = RT_STATE_DEL_PENDING;
00156         }
00157         break;
00158 
00159     case DAX_ITEM_DELETE:
00160         /* One object was deleted. Identifier is the only attribute can be
00161          * retrieved, and it's always returned as a string.
00162          */
00163         if (!dax_get_stringr_by_dwd_ident(dwd, NULL, 0, buf, sizeof(buf))) {
00164             RM_LOG(LOG_ERR, "%s: Read deleted route ERROR!", __func__);
00165             break;
00166         }
00167         RM_TRACE(TF_CONFIG, "%s: Delete route.", __func__);
00168         af = AF_INET;
00169         if (parse_ipaddr(&af, buf, PIF_LEN, &addr, sizeof(addr), NULL,
00170                 &prefix_len, NULL, NULL, 0, NULL, 0) == PARSE_OK) {
00171             rt = config_rt_get(addr, prefix_len);
00172             if (rt) {
00173                 rt->op_state = RT_STATE_DEL_PENDING;
00174             } else {
00175                 RM_LOG(LOG_ERR, "%s: Route 0x%08x/%d doesn't exist!",
00176                         __func__, addr, prefix_len);
00177             }
00178         } else {
00179             RM_LOG(LOG_ERR, "%s: Parse route %s ERROR!", __func__, buf);
00180         }
00181         break;
00182 
00183     case DAX_ITEM_CHANGED:
00184         /* This is a new object or changed object.
00185          * This action is for all configured objects in check mode.
00186          */
00187         rt = calloc(1, sizeof(*rt));
00188         INSIST_ERR(rt);
00189 
00190         /* Get mandatory route destination address. */
00191         if (!dax_get_stringr_by_name(dop, "destination", buf, sizeof(buf))) {
00192             dax_error(dop, "Read route destination ERROR!");
00193             goto ret_err;
00194         }
00195         af = AF_INET;
00196         if (parse_ipaddr(&af, buf, PIF_LEN, &addr, sizeof(addr), NULL,
00197                 &prefix_len, NULL, NULL, 0, NULL, 0) != PARSE_OK) {
00198             dax_error(dop, "Parse route %s ERROR!", buf);
00199             goto ret_err;
00200         }
00201         ssd_setsocktype(&rt->dst_addr, SSD_GF_INET);
00202         rt->dst_addr.in.gin_addr = addr;
00203         rt->prefix_len = prefix_len;
00204 
00205         RM_TRACE(TF_CONFIG, "%s: Change route 0x%08x/%d.", __func__,
00206                 rt->dst_addr.in.gin_addr, rt->prefix_len);
00207 
00208         /* Get mandatory route next-hop type. */
00209         if (!dax_get_ubyte_by_name(dop, "next-hop-type", &rt->nh_type)) {
00210             dax_error(dop, "Read route next-hop type ERROR!");
00211             goto ret_err;
00212         }
00213 
00214         /* Convert next-hop from DDL type to SSD type. */
00215         switch (rt->nh_type) {
00216         case RT_NH_TYPE_UNICAST:
00217             rt->nh_type = SSD_RNH_UNICAST;
00218             break;
00219         case RT_NH_TYPE_REJECT:
00220             rt->nh_type = SSD_RNH_REJECT;
00221             break;
00222         case RT_NH_TYPE_DISCARD:
00223             rt->nh_type = SSD_RNH_DISCARD;
00224             break;
00225         case RT_NH_TYPE_SERVICE:
00226             rt->nh_type = SSD_RNH_SERVICE;
00227             break;
00228         case RT_NH_TYPE_TABLE:
00229             rt->nh_type = SSD_RNH_TABLE;
00230             break;
00231         default:
00232             dax_error(dop, "Unkown route next-hop type %d!", rt->nh_type);
00233             goto ret_err;
00234         }
00235         RM_TRACE(TF_CONFIG, "%s: Change route next-hop type %d.", __func__,
00236                 rt->nh_type);
00237 
00238         /* Get optional route preference. */
00239         if (!dax_get_uint_by_name(dop, "preference", &rt->preference)) {
00240             rt->preference = RM_RT_PREFERENCE_DEFAULT;
00241         }
00242         RM_TRACE(TF_CONFIG, "%s: Change route preference %d.", __func__,
00243                 rt->preference);
00244 
00245         /* Get optional routing table name. */
00246         if (!dax_get_stringr_by_name(dop, "routing-table", buf, sizeof(buf))) {
00247             /* Set the default routing table name. */
00248             sprintf(buf, "inet.0");
00249         }
00250         rt->rtt_id = config_nh_id_get(buf);
00251         RM_TRACE(TF_CONFIG, "%s: Change route routing table %s %d.", __func__,
00252                 buf, rt->rtt_id);
00253 
00254         /* Get optional route state. */
00255         if (dax_get_ushort_by_name(dop, "state", &rt->state)) {
00256 
00257             /* Convert route state from DDL type to SSD type. */
00258             switch (rt->state) {
00259             case RT_STATE_NO_INSTALL:
00260                 rt->state = SSD_RTS_STATE_NOTINSTALL;
00261             case RT_STATE_NO_ADVERTISE:
00262                 rt->state = SSD_RTS_STATE_NOADVISE;
00263             default:
00264                 dax_error(dop, "Unkown route state %d!", rt->state);
00265                 goto ret_err;
00266             }
00267 
00268             /* SSD_RTS_STATE_INTERIOR also needs to be set. */
00269             rt->state |= SSD_RTS_STATE_INTERIOR;
00270 
00271             RM_TRACE(TF_CONFIG, "%s: Change route state 0x%04x.", __func__,
00272                     rt->state);
00273         }
00274 
00275         /* Get optional route flag. */
00276         if (dax_get_ushort_by_name(dop, "flag", &rt->flag)) {
00277 
00278             /* Convert route flag from DDL type to SSD type. */
00279             switch (rt->flag) {
00280             case RT_FLAG_OVER_WRITE:
00281                 rt->flag = SSD_ROUTE_ADD_FLAG_OVERWRITE;
00282             default:
00283                 dax_error(dop, "Unkown route flag %d!", rt->flag);
00284                 goto ret_err;
00285             }
00286             RM_TRACE(TF_CONFIG, "%s: Change route flag %d.", __func__,
00287                     rt->flag);
00288         }
00289 
00290         /* Get route gateways. */
00291         if (dax_get_object_by_path(dop, gateways_config, &dop_gws, FALSE)) {
00292             i = 0;
00293             while (dax_visit_container(dop_gws, &dop_gw)) {
00294                 if (i >= SSD_ROUTE_N_MULTIPATH) {
00295                     dax_error(dop, "Too many gateways!");
00296                     goto ret_err;
00297                 }
00298                 if (dax_get_stringr_by_name(dop_gw, "address", buf,
00299                         sizeof(buf))) {
00300                     af = AF_INET;
00301                     if (parse_ipaddr(&af, buf, PIF_LENOPT, &addr, sizeof(addr),
00302                             NULL, NULL, NULL, NULL, 0, NULL, 0) != PARSE_OK) {
00303                         dax_error(dop, "Parse gateway address %s ERROR!",
00304                                 __func__, buf);
00305                         goto ret_err;
00306                     }
00307                     ssd_setsocktype(&rt->gw_addr[i], SSD_GF_INET);
00308                     rt->gw_addr[i].in.gin_addr = addr;
00309                     RM_TRACE(TF_CONFIG, "%s: Gateway address 0x%08x.",
00310                             __func__, rt->gw_addr[i].in.gin_addr);
00311                 }
00312                 if (dax_get_stringr_by_name(dop_gw, "interface-name",
00313                         rt->gw_ifl_name[i], sizeof(rt->gw_ifl_name[i]))) {
00314                     RM_TRACE(TF_CONFIG, "%s: Gateway IFL name %s.", __func__,
00315                             rt->gw_ifl_name[i]);
00316                 }
00317                 if (dax_get_int_by_name(dop_gw, "interface-index",
00318                         &rt->gw_ifl_idx)) {
00319                     RM_TRACE(TF_CONFIG, "%s: Gateway IFL index %d.", __func__,
00320                             rt->gw_ifl_idx);
00321                 }
00322                 if (dax_get_stringr_by_name(dop_gw, "interface-address", buf,
00323                         sizeof(buf))) {
00324                     af = AF_INET;
00325                     if (parse_ipaddr(&af, buf, PIF_LENOPT, &addr, sizeof(addr),
00326                             NULL, NULL, NULL, NULL, 0, NULL, 0) != PARSE_OK) {
00327                         dax_error(dop, "Parse gateway IFL address %s ERROR!",
00328                                 __func__, buf);
00329                         goto ret_err;
00330                     }
00331                     ssd_setsocktype(&rt->gw_ifl_addr[i], SSD_GF_INET);
00332                     rt->gw_ifl_addr[i].in.gin_addr = addr;
00333                     RM_TRACE(TF_CONFIG, "%s: Gateway IFL address 0x%08x.",
00334                             __func__, rt->gw_ifl_addr[i].in.gin_addr);
00335                 }
00336                 if (dax_get_stringr_by_name(dop_gw, "next-hop", buf,
00337                         sizeof(buf))) {
00338                     rt->nh_id[i] = config_nh_id_get(buf);
00339                     if (rt->nh_id[i] < 0) {
00340                         dax_error(dop, "Next-hop pool is full!");
00341                         goto ret_err;
00342                     }
00343                     RM_TRACE(TF_CONFIG, "%s: Next-hop name %s.", __func__,
00344                             buf);
00345                 } else {
00346                     if (rt->nh_type == SSD_RNH_SERVICE ||
00347                             rt->nh_type == SSD_RNH_TABLE) {
00348                         dax_error(dop, "Next-hop is not configured!");
00349                         goto ret_err;
00350                     }
00351                 }
00352                 i++;
00353             }
00354             rt->gw_num = i;
00355             dax_release_object(&dop_gws);
00356         } else {
00357             if (rt->nh_type == SSD_RNH_UNICAST ||
00358                     rt->nh_type == SSD_RNH_SERVICE ||
00359                     rt->nh_type == SSD_RNH_TABLE) {
00360                 dax_error(dop, "Gateway is not configured!");
00361                 goto ret_err;
00362             }
00363         }
00364         rt->op_state = RT_STATE_ADD_PENDING;
00365         LIST_INSERT_HEAD(&rt_list, rt, entry);
00366         break;
00367     default:
00368         break;
00369     }
00370     return DAX_WALK_OK;
00371 
00372 ret_err:
00373     if (dop_gws) {
00374         dax_release_object(&dop_gws);
00375     }
00376     if (dop_gw) {
00377         dax_release_object(&dop_gw);
00378     }
00379     if (rt) {
00380         free(rt);
00381     }
00382     return DAX_WALK_ABORT;
00383 }
00384 
00395 static int
00396 config_nh_add (route_t *rt)
00397 {
00398     int i;
00399 
00400     RM_TRACE(TF_CONFIG, "%s", __func__);
00401 
00402     /* Add next-hop if it's needed. */
00403     for (i = 0; i < rt->gw_num; i++ ) {
00404         if (rt->nh_id[i] == 0) {
00405             /* No next-hop. */
00406             continue;
00407         }
00408         switch (nh_pool[rt->nh_id[i]].op_state) {
00409         case NH_STATE_ADD_PENDING:
00410             /* Next-hop is allocated, but not being added yet. */
00411             RM_TRACE(TF_CONFIG, "%s: Add next-hop %s", __func__,
00412                     nh_pool[rt->nh_id[i]].name);
00413             if (ssd_nh_add(rt, rt->nh_id[i]) >= 0) {
00414                 rt->ctx_id = rt->nh_id[i];
00415                 /* Add one next-hop at each time. */
00416                 return 0;
00417             }
00418             RM_LOG(LOG_ERR, "%s: Add next-hop ERROR!");
00419             /* Fall through. */
00420         case NH_STATE_ADD_ERR:
00421             /* Tried to add next-hop or request routing table ID,
00422              * but failed, then free it.
00423              */
00424             nh_pool[rt->nh_id[i]].op_state = NH_STATE_FREE;
00425             /* Adding next-hop failed. */
00426             return -1;
00427         case NH_STATE_ADD_OK:
00428         default:
00429             break;;
00430         }
00431     }
00432     /* All next-hop are added. */
00433     rt->ctx_id = 0;
00434     return 0;
00435 }
00436 
00447 static int
00448 config_nh_del (route_t *rt)
00449 {
00450     int i;
00451 
00452     /* See if any next-hop needs to be deleted. */
00453     for (i = 0; i < rt->gw_num; i++) {
00454         if (rt->nh_id[i] == 0) {
00455             /* No next-hop. */
00456             continue;
00457         }
00458         if (--nh_pool[rt->nh_id[i]].count > 0) {
00459             /* The next-hop is still refered by other routes. */
00460             continue;
00461         }
00462         switch (nh_pool[rt->nh_id[i]].op_state) {
00463         case NH_STATE_ADD_OK:
00464             /* The next-hop reference counter is 0. */
00465             if (ssd_nh_del(rt, rt->nh_id[i]) == 0) {
00466                 /* Delete next-hop one at each time. */
00467                 rt->ctx_id = rt->nh_id[i];
00468                 return 0;
00469             }
00470             RM_LOG(LOG_ERR, "%s: Delete next-hop ERROR", __func__);
00471         case NH_STATE_DEL_ERR:
00472             /* Leave it in kernel, fall through. */
00473         case NH_STATE_DEL_OK:
00474             nh_pool[rt->nh_id[i]].op_state = NH_STATE_FREE;
00475         default:
00476             break;
00477         }
00478     }
00479     rt->ctx_id = 0;
00480     return 0;
00481 }
00482 
00493 int
00494 config_rt_del (route_t *rt)
00495 {
00496     if (!rt) {
00497         return -1;
00498     }
00499 
00500     switch (rt->op_state) {
00501     case RT_STATE_DEL_PENDING:
00502         if (ssd_rt_del(rt) < 0) {
00503             goto ret_err; 
00504         }
00505         break;
00506     case RT_STATE_DEL_OK:
00507         config_nh_del(rt);
00508         if (rt->ctx_id == 0) {
00509             /* No next-hop needs to be deleted. */
00510             return -1;
00511         }
00512     default:
00513         break;
00514     }
00515     return 0;
00516 
00517 ret_err:
00518     rt->op_state = RT_STATE_DEL_ERR;
00519     return -1;
00520 }
00521 
00532 int
00533 config_rt_add (route_t *rt)
00534 {
00535     if (!rt) {
00536         return -1;
00537     }
00538 
00539     /* The operation state is always add-pending. */
00540     /* Check routing table ID. */
00541     if (nh_pool[rt->rtt_id].idx == 0) {
00542         RM_TRACE(TF_CONFIG, "%s: Request routing table %s ID.", __func__,
00543                 nh_pool[rt->rtt_id].name);
00544         /* Request routing table ID. */
00545         if (ssd_nh_add(rt, rt->rtt_id) < 0) {
00546             RM_LOG(LOG_ERR, "%s: Request routing table %s ID ERROR!",
00547                     __func__, nh_pool[rt->rtt_id].name);
00548             goto ret_err;
00549         }
00550         rt->ctx_id = rt->rtt_id;
00551         /* Request routing table ID, leave the rest to the reply callback. */
00552     } else {
00553         if (config_nh_add(rt) < 0) {
00554             /* Adding next-hop failed. */
00555             goto ret_err;
00556         }
00557         if (rt->ctx_id == 0) {
00558             /* All next-hops are added, go ahead to add the route. */
00559             if (ssd_rt_add(rt) < 0) {
00560                 RM_LOG(LOG_ERR, "%s: Add route 0x%08x ERROR!", __func__,
00561                         rt->dst_addr.in.gin_addr);
00562                 goto ret_err;
00563             }
00564         }
00565         /* Add next-hop, leave the rest to the reply handler. */
00566     }
00567     return 0;
00568 
00569 ret_err:
00570     rt->op_state = RT_STATE_ADD_ERR;
00571     return -1;
00572 }
00573 
00579 void
00580 config_rt_proc (route_t *rt)
00581 {
00582     int i;
00583 
00584     if (!rt) {
00585         /* Process the first route. */
00586         rt = LIST_FIRST(&rt_list);
00587         if (!rt) {
00588             RM_LOG(LOG_ERR, "%s: The route list is empty!", __func__);
00589             return;
00590         }
00591     }
00592 
00593 proc_continue:
00594     RM_TRACE(TF_CONFIG, "%s: Process route %08x.", __func__,
00595             rt->dst_addr.in.gin_addr);
00596     switch (rt->op_state) {
00597     case RT_STATE_ADD_OK:
00598         /* Adding route is done. */
00599         /* Update next-hop reference count. */
00600         RM_TRACE(TF_CONFIG, "%s: Add route %08x OK.", __func__,
00601                 rt->dst_addr.in.gin_addr);
00602         for (i = 0; i < rt->gw_num; i++) {
00603             nh_pool[rt->nh_id[i]].count++;
00604         }
00605         /* Fall through to add the next. */
00606     case RT_STATE_ADD_ERR:
00607         RM_TRACE(TF_CONFIG, "%s: Add route %08x ERROR.", __func__,
00608                 rt->dst_addr.in.gin_addr);
00609         /* Keeping adding the next. */
00610         rt = LIST_NEXT(rt, entry);
00611         if (!rt) {
00612             /* All done. */
00613             break;
00614         }
00615         /* Fall through to add. */
00616     case RT_STATE_ADD_PENDING:
00617         /* Start or continue adding. */
00618         RM_TRACE(TF_CONFIG, "%s: Add route %08x.", __func__,
00619                 rt->dst_addr.in.gin_addr);
00620         if (config_rt_add(rt) < 0) {
00621             goto proc_continue;
00622         }
00623         break;
00624     case RT_STATE_DEL_OK:
00625         /* Check next-hop if there is any. */
00626         if (config_rt_del(rt) >= 0) {
00627             /* There is next-hop to be deleted. */
00628             break;
00629         }
00630         /* No next-hop need to be deleted, fall through. */
00631     case RT_STATE_DEL_ERR:
00632         /* Free the route from local database. */
00633         LIST_REMOVE(rt, entry);
00634         free(rt);
00635         rt = LIST_FIRST(&rt_list);
00636         if (!rt) {
00637             /* All done. */
00638             break;
00639         }
00640         /* Fall through to delete. */
00641     case RT_STATE_DEL_PENDING:
00642         /* Start or continue deleting. */
00643         if (config_rt_del(rt) < 0) {
00644             goto proc_continue;
00645         }
00646         break;
00647     default:
00648         break;
00649     }
00650 }
00651 
00664 int
00665 config_read (int check)
00666 {
00667     const char *routes_config[] = { "sync", "route-manager", "routes", NULL };
00668     ddl_handle_t *dop = NULL;
00669     int rc = 0;
00670 
00671     RM_TRACE(TF_CONFIG, "%s: Read configuration.", __func__);
00672     if (dax_get_object_by_path(NULL, routes_config, &dop, FALSE)) {
00673         if (check) {
00674             /* In check mode, all objects are new to the spawned process
00675              * that doesn't have previous states. So with DAX_WALK_CHANGED,
00676              * the handler will be called for each configured object with
00677              * DAX_ITEM_CHANGED action. The handler won't be called for
00678              * deleted objects.
00679              */
00680             rc = dax_walk_list(dop, DAX_WALK_CHANGED, config_rt_read, NULL);
00681         } else {
00682             /* In SIGHUP mode, the handler will be called for each added
00683              * or changed object with DAX_ITEM_CHANGED action, for each
00684              * deleted object with DAX_ITEM_DELETED action.
00685              */
00686             rc = dax_walk_list(dop, DAX_WALK_DELTA, config_rt_read, NULL);
00687         }
00688 
00689         dax_release_object(&dop);
00690     }
00691     if (rc == DAX_WALK_OK) {
00692         RM_TRACE(TF_CONFIG, "%s: check %d, svc_ready %d.", __func__, check,
00693                 svc_ready);
00694         if (!check && svc_ready) {
00695             config_rt_proc(NULL);
00696         }
00697         return 0;
00698     } else {
00699         return -1;
00700     }
00701 }
00702 
00708 void
00709 config_clear (void)
00710 {
00711     route_t *rt;
00712 
00713     while ((rt = LIST_FIRST(&rt_list))) {
00714         LIST_REMOVE(rt, entry);
00715         free(rt);
00716     }
00717 }
00718 
00728 int
00729 config_init (void)
00730 {
00731     bzero(nh_pool, sizeof(nh_pool));
00732     return 0;
00733 }
00734 

2007-2009 Juniper Networks, Inc. All rights reserved. The information contained herein is confidential information of Juniper Networks, Inc., and may not be used, disclosed, distributed, modified, or copied without the prior written consent of Juniper Networks, Inc. in an express license. This information is subject to change by Juniper Networks, Inc. Juniper Networks, the Juniper Networks logo, and JUNOS are registered trademarks of Juniper Networks, Inc. in the United States and other countries. All other trademarks, service marks, registered trademarks, or registered service marks are the property of their respective owners.
Generated on Sun May 30 20:27:07 2010 for SDK Your Net Corporation Route Manager: route-manager 1.0 by Doxygen 1.5.1