00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00022 #include <sync/common.h>
00023 #include <jnx/ssd_ipc.h>
00024 #include <jnx/ssd_ipc_msg.h>
00025 #include <limits.h>
00026 #include "ped_ssd.h"
00027
00028 #include PE_OUT_H
00029 #include PE_SEQUENCE_H
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #define RT_TBL_NAME "inet.0"
00042
00043
00046 #define REQUESTS_BUFFER_SIZE 64
00047
00052 #define UNCONFIRMED_CONTEXT REQUESTS_BUFFER_SIZE
00053
00057 #define MAX_UNCONFIRMED_CONTEXT UINT_MAX
00058
00062 #define RETRY_CONNECT 60
00063
00064
00065
00066
00067 static boolean ssd_ready = FALSE;
00068 static int ssd_server_fd = -1;
00069 static int client_id = 0;
00070 static uint32_t rt_tbl_id = 0;
00071 static evTimerID timer_id;
00072
00073
00074
00075 static int ssd_client_connection(int fd);
00076 static void ssd_client_connection_close(int fd, int cause);
00077 static void ssd_client_msg(int fd, struct ssd_ipc_msg *cmsg);
00078
00082 static struct ssd_ipc_ft ssd_client_ft = {
00083 ssd_client_connection,
00084 ssd_client_connection_close,
00085 ssd_client_msg
00086 };
00087
00088 extern evContext ped_ctx;
00089
00094 typedef struct {
00095 ssd_reply_notification_handler reply_handler;
00096 void * user_data;
00097 } ssd_request_t;
00098
00099 static ssd_request_t ssd_requests[REQUESTS_BUFFER_SIZE];
00100 static uint32_t next_buffer = 0;
00101 static uint32_t next_unconfirmed = UNCONFIRMED_CONTEXT;
00102 static int outstanding_requests = 0;
00103
00104
00105
00106
00107
00127 static void
00128 connect_ssd(evContext ctx __unused,
00129 void * uap __unused,
00130 struct timespec due __unused,
00131 struct timespec inter __unused)
00132 {
00133 int rt_table_id;
00134
00135 if(ssd_server_fd >= 0) {
00136 return;
00137 }
00138
00139
00140
00141 rt_table_id = ssd_get_routing_instance();
00142 ssd_server_fd = ssd_ipc_connect_rt_tbl(NULL, &ssd_client_ft,
00143 rt_table_id, ped_ctx);
00144
00145 if (ssd_server_fd < 0) {
00146 ERRMSG(PED, TRACE_LOG_ERR,
00147 "%s: Opening socket to SSD failed! Will retry.", __func__);
00148 return;
00149 }
00150
00151 evClearTimer(ped_ctx, timer_id);
00152
00153 junos_trace(PED_TRACEFLAG_ROUTING, "%s: Connected to SSD", __func__);
00154 }
00155
00156
00161 static int
00162 ssd_client_connection(int fd)
00163 {
00164
00165
00166 if(ssd_get_client_id(fd, 0) < 0) {
00167 ERRMSG(PED, TRACE_LOG_ERR,
00168 "%s: Error requesting client ID from SSD %m",
00169 __func__);
00170
00171 return -1;
00172 }
00173
00174 junos_trace(PED_TRACEFLAG_ROUTING,
00175 "%s: SSD connected.", __func__);
00176
00177 return SUCCESS;
00178 }
00179
00180
00190 static void
00191 ssd_client_connection_close(int fd __unused, int cause __unused)
00192 {
00193 ssd_server_fd = -1;
00194 ssd_ready = FALSE;
00195
00196
00197
00198
00199
00200
00201
00202
00203 if(evSetTimer(ped_ctx, connect_ssd, NULL, evNowTime(),
00204 evConsTime(RETRY_CONNECT, 0), &timer_id)) {
00205
00206 ERRMSG(PED, TRACE_LOG_ERR,
00207 "%s: evSetTimer() FAILED! Will not be able to connect "
00208 "to the SSD", __func__);
00209 }
00210
00211 junos_trace(PED_TRACEFLAG_ROUTING,
00212 "%s: SSD disconnected.", __func__);
00213
00214 junos_trace(PED_TRACEFLAG_ROUTING,
00215 "PED's SSD module is NOT accepting "
00216 "route add/delete requests");
00217 }
00218
00219
00229 static void
00230 ssd_client_msg (int fd, struct ssd_ipc_msg * cmsg)
00231 {
00232 char * rt_tb_name = NULL;
00233 unsigned int context;
00234
00235 switch (cmsg->ssd_ipc_cmd) {
00236
00237 case SSD_SESSION_ID_REPLY:
00238
00239 if(SSD_SESSION_ID_REPLY_CHECK_STATUS(cmsg)) {
00240
00241 client_id = SSD_SESSION_ID_REPLY_GET_CLIENT_ID(cmsg);
00242
00243 junos_trace(PED_TRACEFLAG_ROUTING,
00244 "%s: Received client id from SSD : %u",
00245 __func__, client_id);
00246
00247
00248
00249 if(ssd_setup_route_service(fd) < 0) {
00250 ERRMSG(PED, TRACE_LOG_ERR, "%s: Error requesting route "
00251 "service setup from SSD %m", __func__);
00252 }
00253 } else {
00254 ERRMSG(PED, TRACE_LOG_ERR,
00255 "%s: Error getting client ID from SSD", __func__);
00256 }
00257 break;
00258
00259 case SSD_ROUTE_SERVICE_REPLY:
00260
00261 if(SSD_ROUTE_SERVICE_REPLY_CHECK_STATUS(cmsg)) {
00262
00263 rt_tb_name = strdup(RT_TBL_NAME);
00264 INSIST(rt_tb_name != NULL);
00265
00266 junos_trace(PED_TRACEFLAG_ROUTING,
00267 "%s: Route service has been setup properly",
00268 __func__);
00269
00270
00271
00272 if(ssd_request_route_table_lookup(
00273 fd, rt_tb_name, 0) < 0) {
00274
00275 ERRMSG(PED, TRACE_LOG_ERR, "%s: Error requesting route "
00276 "table lookup from SSD %m", __func__);
00277 }
00278 } else {
00279 ERRMSG(PED, TRACE_LOG_ERR,
00280 "%s: Error setting up route service with SSD", __func__);
00281 }
00282 break;
00283
00284 case SSD_ROUTE_TABLE_LOOKUP_REPLY:
00285
00286 if(SSD_ROUTE_TABLE_LOOKUP_REPLY_CHECK_STATUS(cmsg)) {
00287
00288 rt_tbl_id = SSD_ROUTE_TABLE_LOOKUP_REPLY_GET_RTTID(cmsg);
00289
00290 junos_trace(PED_TRACEFLAG_ROUTING,
00291 "%s: Route table is found id %u",
00292 __func__, rt_tbl_id);
00293
00294
00295
00296 ssd_ready = TRUE;
00297
00298 junos_trace(PED_TRACEFLAG_ROUTING,
00299 "PED's SSD module is ready to accept "
00300 "route add/delete requests");
00301 } else {
00302 ERRMSG(PED, TRACE_LOG_ERR,
00303 "%s: Error getting route table from SSD %d",
00304 __func__, SSD_ROUTE_TABLE_LOOKUP_REPLY_GET_ERROR_CODE(cmsg));
00305 }
00306 break;
00307
00308 case SSD_ROUTE_ADD_REPLY:
00309
00310 context = SSD_ROUTE_ADD_REPLY_GET_CLIENT_CTX(cmsg);
00311
00312
00313 INSIST(context < REQUESTS_BUFFER_SIZE);
00314
00315 if(SSD_ROUTE_ADD_REPLY_CHECK_STATUS(cmsg)) {
00316 junos_trace(PED_TRACEFLAG_ROUTING,
00317 "%s: Route add success", __func__);
00318
00319 ssd_requests[context].reply_handler(
00320 ADD_SUCCESS, ssd_requests[context].user_data);
00321
00322 } else {
00323 junos_trace(PED_TRACEFLAG_ROUTING,
00324 "%s: Route add failed", __func__);
00325
00326 ssd_requests[context].reply_handler(
00327 ADD_FAILED, ssd_requests[context].user_data);
00328 }
00329
00330
00331 ssd_requests[context].reply_handler = NULL;
00332 ssd_requests[context].user_data = NULL;
00333 --outstanding_requests;
00334
00335 break;
00336
00337 case SSD_ROUTE_DELETE_REPLY:
00338
00339 context = SSD_ROUTE_DELETE_REPLY_GET_CLIENT_CTX(cmsg);
00340
00341 if(SSD_ROUTE_DELETE_REPLY_CHECK_STATUS(cmsg)) {
00342
00343 if(context < REQUESTS_BUFFER_SIZE) {
00344
00345 junos_trace(PED_TRACEFLAG_ROUTING, "%s: Route delete success "
00346 "(with confirmation)", __func__);
00347
00348
00349 ssd_requests[context].reply_handler(
00350 DELETE_SUCCESS, ssd_requests[context].user_data);
00351
00352
00353 ssd_requests[context].reply_handler = NULL;
00354 ssd_requests[context].user_data = NULL;
00355 --outstanding_requests;
00356
00357 } else {
00358 junos_trace(PED_TRACEFLAG_ROUTING, "%s: Route delete success "
00359 "(without confirmation)", __func__);
00360 }
00361 } else {
00362 if(context < REQUESTS_BUFFER_SIZE) {
00363
00364 junos_trace(PED_TRACEFLAG_ROUTING, "%s: Route delete failed "
00365 "(with confirmation)", __func__);
00366
00367
00368 ssd_requests[context].reply_handler(
00369 DELETE_FAILED, ssd_requests[context].user_data);
00370
00371
00372 ssd_requests[context].reply_handler = NULL;
00373 ssd_requests[context].user_data = NULL;
00374 --outstanding_requests;
00375
00376 } else {
00377 ERRMSG(PED, TRACE_LOG_ERR,
00378 "%s: Route delete failed (without confirmation)."
00379 "WARNING: dangling route.", __func__);
00380 }
00381 }
00382
00383 break;
00384
00385 case SSD_ROUTE_SERVICE_CLEAN_UP_REPLY:
00386
00387 break;
00388
00389 default:
00390
00391 ERRMSG(PED, TRACE_LOG_ERR, "%s: Unknown message type %d",
00392 __func__, cmsg->ssd_ipc_args[0]);
00393
00394 }
00395 }
00396
00397
00410 static int
00411 ssd_client_ifa_handler(kcom_ifa_t * msg, void * user_info )
00412 {
00413 policy_route_msg_t *route = (policy_route_msg_t *)user_info;
00414 ssd_sockaddr_un route_addr;
00415 ssd_sockaddr_un route_nh;
00416 ssd_sockaddr_un route_local;
00417 struct ssd_route_parms rtp;
00418 struct in_addr addr;
00419
00420
00421
00422 bzero(&route_addr, sizeof(route_addr));
00423 ssd_setsocktype(&route_addr, SSD_GF_INET);
00424 route_addr.in.gin_addr = route->route_addr;
00425
00426 bzero(&route_nh, sizeof(route_nh));
00427 ssd_setsocktype(&route_nh, SSD_GF_INET);
00428 route_nh.in.gin_addr = route->nh_addr;
00429
00430 bzero(&route_local, sizeof(route_local));
00431 ssd_setsocktype(&route_local, SSD_GF_INET);
00432 route_local.in.gin_addr = *(in_addr_t *)(msg->ifa_lprefix);
00433
00434
00435
00436 bzero(&rtp, sizeof(rtp));
00437 rtp.rta_dest = &route_addr;
00438 rtp.rta_prefixlen = route->route_addr_prefix;
00439
00440 if(route->preferences) {
00441 rtp.rta_preferences.rtm_val[0] = route->preferences;
00442 rtp.rta_preferences.rtm_type[0] = SSD_RTM_VALUE_PRESENT;
00443 }
00444
00445 if(route->metrics) {
00446 rtp.rta_metrics.rtm_val[0] = route->metrics;
00447 rtp.rta_metrics.rtm_type[0] = SSD_RTM_VALUE_PRESENT;
00448 }
00449
00450
00451 rtp.rta_rtt = rt_tbl_id;
00452 rtp.rta_nhtype = route->nh_type;
00453 if(route->nh_addr) {
00454 rtp.rta_n_gw = 1;
00455 rtp.rta_gateway[0].rtg_gwaddr = &route_nh;
00456 rtp.rta_gateway[0].rtg_ifl = msg->ifa_index;
00457 rtp.rta_gateway[0].rtg_lcladdr = &route_local;
00458 }
00459
00460 addr.s_addr = route->route_addr;
00461
00462 junos_trace(PED_TRACEFLAG_ROUTING,
00463 "%s: route address: %s/%d", __func__,
00464 inet_ntoa(addr), route->route_addr_prefix);
00465
00466 addr.s_addr = *(in_addr_t *)(msg->ifa_lprefix);
00467
00468 junos_trace(PED_TRACEFLAG_ROUTING,
00469 "%s: local address: %s, ifl: %d", __func__,
00470 inet_ntoa(addr), msg->ifa_index);
00471
00472 addr.s_addr = route->nh_addr;
00473
00474 junos_trace(PED_TRACEFLAG_ROUTING,
00475 "%s: nh: %s, m: %d, p: %d", __func__,
00476 inet_ntoa(addr), route->metrics, route->preferences);
00477
00478
00479 if(ssd_request_route_add(ssd_server_fd, &rtp, next_buffer) < 0) {
00480
00481 ERRMSG(PED, TRACE_LOG_ERR,
00482 "%s: Error requesting route add from SSD: %m", __func__);
00483
00484 junos_kcom_msg_free(msg);
00485
00486 return 1;
00487 }
00488
00489 junos_kcom_msg_free(msg);
00490
00491 return SUCCESS;
00492 }
00493
00494
00495
00496
00497
00501 void
00502 ped_ssd_init(void)
00503 {
00504 int i = 0;
00505
00506 ssd_server_fd = -1;
00507 client_id = 0;
00508 rt_tbl_id = 0;
00509 next_buffer = 0;
00510 next_unconfirmed = UNCONFIRMED_CONTEXT;
00511 outstanding_requests = 0;
00512
00513 for(; i < REQUESTS_BUFFER_SIZE; ++i) {
00514 ssd_requests[i].reply_handler = NULL;
00515 ssd_requests[i].user_data = NULL;
00516 }
00517
00518
00519
00520
00521
00522
00523
00524
00525 if(evSetTimer(ped_ctx, connect_ssd, NULL, evNowTime(),
00526 evConsTime(RETRY_CONNECT, 0), &timer_id)) {
00527
00528 ERRMSG(PED, TRACE_LOG_ERR,
00529 "%s: evSetTimer() FAILED! Will not be able to connect "
00530 "to the SSD", __func__);
00531 }
00532 }
00533
00534
00538 void
00539 ped_ssd_shutdown(void)
00540 {
00541 if(ssd_server_fd != -1) {
00542 ssd_ipc_close(ssd_server_fd);
00543 }
00544 }
00545
00546
00553 boolean
00554 get_ssd_ready(void)
00555 {
00556 return ssd_ready;
00557 }
00558
00559
00567 boolean
00568 get_ssd_idle(void)
00569 {
00570 return outstanding_requests < 1;
00571 }
00572
00573
00590 boolean
00591 ssd_client_add_route_request(
00592 policy_route_msg_t *route,
00593 ssd_reply_notification_handler func,
00594 void * user_data)
00595 {
00596 kcom_ifl_t ifl;
00597 char * dot;
00598 if_subunit_t unit = -1;
00599 long tmp;
00600 int rc;
00601
00602 INSIST(route != NULL);
00603 INSIST(ssd_ready);
00604 INSIST(func != NULL);
00605
00606
00607 if(ssd_requests[next_buffer].reply_handler != NULL) {
00608
00609
00610
00611 ERRMSG(PED, TRACE_LOG_WARNING,
00612 "%s: Warning: PED's ssd module has run "
00613 "out of space to hold more requests! Either it "
00614 "is being flooded or SSD responses are very delayed!",
00615 __func__);
00616
00617 return FALSE;
00618 }
00619
00620
00621 ssd_requests[next_buffer].reply_handler = func;
00622 ssd_requests[next_buffer].user_data = user_data;
00623
00624 junos_trace(PED_TRACEFLAG_ROUTING,
00625 "%s: Adding route", __func__);
00626
00627
00628
00629 if((dot = strchr(route->ifname, '.')) != NULL) {
00630 *dot = '\0';
00631 unit = ((tmp = atol(++dot)) < 1) ? 0 : (if_subunit_t)tmp;
00632 } else {
00633 unit = 0;
00634 }
00635
00636 if(junos_kcom_ifl_get_by_name(route->ifname, unit, &ifl)) {
00637
00638 ERRMSG(PED, TRACE_LOG_ERR,
00639 "%s: Get ifl by name FAILED!", __func__);
00640
00641 ssd_requests[next_buffer].reply_handler = NULL;
00642 ssd_requests[next_buffer].user_data = NULL;
00643
00644 return FALSE;
00645 }
00646
00647 if((rc = junos_kcom_ifa_get_all(ssd_client_ifa_handler,
00648 ifl.ifl_index, route->af, route)) > SUCCESS) {
00649
00650 ssd_requests[next_buffer].reply_handler = NULL;
00651 ssd_requests[next_buffer].user_data = NULL;
00652
00653 return FALSE;
00654
00655 } else if(rc < SUCCESS) {
00656
00657 ssd_requests[next_buffer].reply_handler = NULL;
00658 ssd_requests[next_buffer].user_data = NULL;
00659
00660 ERRMSG(PED, TRACE_LOG_ERR,
00661 "%s: Could not go through IFAs to add route", __func__);
00662
00663 return FALSE;
00664 }
00665
00666 ++next_buffer;
00667 ++outstanding_requests;
00668
00669 if(next_buffer >= REQUESTS_BUFFER_SIZE)
00670 next_buffer = 0;
00671
00672 return TRUE;
00673 }
00674
00675
00699 boolean
00700 ssd_client_del_route_request(
00701 policy_route_msg_t *route,
00702 ssd_reply_notification_handler func,
00703 void * user_data)
00704 {
00705 ssd_sockaddr_un route_addr;
00706 struct ssd_rt_delete_parms rtp;
00707 struct in_addr addr;
00708
00709 INSIST(route != NULL);
00710 INSIST(ssd_ready);
00711
00712 INSIST(func != NULL || user_data == NULL);
00713
00714
00715 addr.s_addr = route->route_addr;
00716
00717 junos_trace(PED_TRACEFLAG_ROUTING,
00718 "%s: deleting route with address: %s/%d", __func__,
00719 inet_ntoa(addr), route->route_addr_prefix);
00720
00721 bzero(&route_addr, sizeof(route_addr));
00722 ssd_setsocktype(&route_addr, SSD_GF_INET);
00723 route_addr.in.gin_addr = route->route_addr;
00724
00725 rtp.rtd_dest = &route_addr;
00726 rtp.rtd_prefixlen = route->route_addr_prefix;
00727 rtp.rtd_rtt = rt_tbl_id;
00728
00729
00730 if(func != NULL) {
00731
00732
00733 if(ssd_requests[next_buffer].reply_handler != NULL) {
00734
00735
00736
00737 ERRMSG(PED, TRACE_LOG_WARNING,
00738 "%s: Warning: PED's ssd module has run "
00739 "out of space to hold more requests! Either it "
00740 "is being flooded or SSD responses are very delayed!",
00741 __func__);
00742
00743 return FALSE;
00744 }
00745
00746
00747 ssd_requests[next_buffer].reply_handler = func;
00748 ssd_requests[next_buffer].user_data = user_data;
00749
00750
00751 if(ssd_request_route_delete(ssd_server_fd, &rtp, next_buffer)) {
00752
00753 ERRMSG(PED, TRACE_LOG_ERR,
00754 "%s: Error requesting route delete from SSD: %m", __func__);
00755
00756 ssd_requests[next_buffer].reply_handler = NULL;
00757 ssd_requests[next_buffer].user_data = NULL;
00758
00759 return FALSE;
00760 }
00761
00762 ++next_buffer;
00763 ++outstanding_requests;
00764
00765 if(next_buffer >= REQUESTS_BUFFER_SIZE)
00766 next_buffer = 0;
00767
00768 } else {
00769 if(next_unconfirmed >= MAX_UNCONFIRMED_CONTEXT) {
00770 next_unconfirmed = UNCONFIRMED_CONTEXT;
00771 }
00772
00773 if(ssd_request_route_delete(ssd_server_fd, &rtp, next_unconfirmed)) {
00774
00775 ERRMSG(PED, TRACE_LOG_ERR,
00776 "%s: Error requesting route delete from SSD: %m", __func__);
00777
00778 return FALSE;
00779 }
00780 }
00781
00782 return TRUE;
00783 }
00784
00785
00789 void
00790 clean_routes(void)
00791 {
00792 int rc;
00793
00794 if(ssd_ready) {
00795 junos_trace(PED_TRACEFLAG_ROUTING,
00796 "%s: SSD module is shutting down", __func__);
00797
00798 rc = ssd_clean_up_route_service(ssd_server_fd, MAX_UNCONFIRMED_CONTEXT);
00799 if(rc == -1) {
00800 ERRMSG(PED, TRACE_LOG_ERR,
00801 "%s: Route service could not issue clean-up due to error: %m",
00802 __func__);
00803 }
00804 }
00805 }