1/* 2 * Copyright (c) 2007-12 ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <sys/endian.h> 11#include <barrelfish/barrelfish.h> 12#include <barrelfish/waitset.h> 13#include <barrelfish/nameservice_client.h> 14#include <barrelfish/net_constants.h> 15#include <barrelfish/bulk_transfer.h> 16//#include <net_device_manager/net_ports_service.h> 17#include <if/net_soft_filters_defs.h> 18#include <if/net_soft_filters_defs.h> 19//#include <if/net_ports_defs.h> 20 21// For filter generation 22#include <bfdmuxtools/tools.h> 23#include <bfdmuxtools/codegen.h> 24 25#include <stdio.h> 26#include <string.h> 27#include <arpa/inet.h> 28 29#include "port_management_support.h" 30#include "device_manager_debug.h" 31 32 33#define NORMAL_FILTER (1) 34#define REDIRECT_FILTER (2) 35 36/**************************************************************** 37* Local states 38*****************************************************************/ 39 40// handle for connection with soft filters service. 41static struct net_soft_filters_binding *soft_filters_connection = NULL; 42 43static bool soft_filters_ready = false; 44// bulk_transfer used to move the packet filters between net_device_manager 45// and queue_manager 46static struct bulk_transfer bt_filter_tx; 47 48static bool filter_mem_lock = true; // protects the above filter memory 49 50 51// Local ip address assigned to the interface 52struct ip_addr local_ip = { 53 .addr = BFDMUX_IP_ADDR_ANY 54 }; 55 56static bool valid_mac_addr_assigned = false; // marks valid mac address 57static struct eth_addr mac; // = { .addr = {0, 0, 0, 0, 0, 0}}; 58 59// ***************************************************************** 60// * related to managing soft filters 61// ***************************************************************** 62 63static uint64_t populate_rx_tx_filter_mem(uint16_t port, 64 net_ports_port_type_t type, int32_t *len_rx, int32_t *len_tx); 65 66static void connect_soft_filters_service(char *dev_name, qid_t qid); 67static void register_arp_soft_filter(uint64_t id, uint64_t len_rx, 68 uint64_t len_tx); 69 70static errval_t register_soft_filt_impl(uint16_t port, 71 port_type_t type, 72 bufid_t buffer_id_rx, 73 bufid_t buffer_id_tx, 74 appid_t appid, 75 qid_t qid, 76 uint64_t *id, errval_t *rerr, uint64_t *filter_id); 77 78static errval_t unregister_soft_filter(uint64_t filter_id, qid_t qid); 79 80static struct filters_tx_vtbl soft_filts_mng = { 81 .type = "Soft_filters", 82 .init_filters = connect_soft_filters_service, 83 .reg_arp_filters = register_arp_soft_filter, 84 .reg_filters = register_soft_filt_impl, 85 .unreg_filters = unregister_soft_filter, 86}; 87 88/***************************************************************** 89* Prototypes 90*****************************************************************/ 91static void share_common_memory_with_filter_manager(void); 92static void sf_mac_lookup(void); 93 94static void send_soft_filter(uint64_t id, uint64_t len_rx, uint64_t len_tx, 95 uint64_t buffer_id_rx, uint64_t buffer_id_tx, 96 uint8_t ftype, uint8_t paused, 97 errval_t *rerr, uint64_t *filter_id); 98 99// ***************************************************************** 100// * Get signature of this service 101// ***************************************************************** 102struct filters_tx_vtbl *get_soft_filt_mng_sign(void) 103{ 104 return &soft_filts_mng; 105} // end function: get_filt_mng_sign 106 107 108// ***************************************************************** 109// * converting port requests into filters 110// ***************************************************************** 111 112 113static errval_t register_soft_filt_impl(uint16_t port, 114 port_type_t type, 115 bufid_t buffer_id_rx, 116 bufid_t buffer_id_tx, 117 appid_t appid, 118 qid_t qid, 119 uint64_t *id, errval_t *rerr, uint64_t *filter_id) 120{ 121 int32_t len_rx, len_tx; 122 /* NOTE: check if someone else is using the filter location */ 123 if (filter_mem_lock) { 124 /* FIXME: as there is only one registered location for filter 125 transfer, only one filter registration can be done at one time. */ 126 NDM_DEBUG("filter memory is busy.\n"); 127 return FILTER_ERR_FILTER_BUSY; 128 } 129 130 /* create rx, tx filter around that port */ 131 filter_mem_lock = true; /* NOTE: filter memory is in use 132 till "registered_filter" is called by filter_manager */ 133 *id = populate_rx_tx_filter_mem(port, type, &len_rx, &len_tx); 134 135 /* Register the filter with soft_filters */ 136 NDM_DEBUG("get_port: trying to register the filter with id %" PRIu64 "\n", 137 *id); 138 send_soft_filter(*id, len_rx, len_tx, buffer_id_rx, buffer_id_tx, 139 NORMAL_FILTER, 0, rerr, filter_id); 140 141 return SYS_ERR_OK; 142} 143 144 145// ***************************************************************** 146// * Connect with soft filter service 147// ***************************************************************** 148 149static void soft_filters_bind_cb(void *st, errval_t err, 150 struct net_soft_filters_binding *enb) 151{ 152 if (err_is_fail(err)) { 153 DEBUG_ERR(err, "bind failed"); 154 abort(); 155 } 156 NDM_DEBUG("soft_filters_bind_cb: started\n"); 157 158 net_soft_filters_rpc_client_init(enb); 159 160 soft_filters_connection = enb; 161 NDM_DEBUG(" soft_filters_bind_cb: connection made," 162 " now registering memory \n"); 163 NDM_DEBUG("soft_filters_bind_cb: terminated\n"); 164} 165 166 167// \brief: Establishes connection with soft_filters service 168static void connect_soft_filters_service(char *dev_name, qid_t qid) 169{ 170 assert(dev_name != NULL); 171 NDM_DEBUG("c_sf_mng: connecting to dev [%s]\n", dev_name); 172 173 errval_t err; 174 175 // The service name 176 char service_name[MAX_NET_SERVICE_NAME_LEN]; 177 178 snprintf(service_name, sizeof(service_name), "%s_%" PRIu64 "%s", 179 dev_name, qid, FILTER_SERVICE_SUFFIX); 180 NDM_DEBUG("c_sf_mng: resolving service [%s]\n", service_name); 181 182 // locate the service 183 iref_t iref = 0; 184 err = nameservice_blocking_lookup(service_name, &iref); 185 if (err_is_fail(err)) { 186 DEBUG_ERR(err, "c_sf_mng: could not connect to soft filter manager .\n" 187 "Terminating.\n"); 188 abort(); 189 } 190 assert(iref != 0); 191 192 // Connect to the service 193 NDM_DEBUG("c_sf_mng: connecting\n"); 194 195 err = net_soft_filters_bind(iref, soft_filters_bind_cb, NULL, 196 get_default_waitset(), IDC_BIND_FLAGS_DEFAULT); 197 assert(err_is_ok(err)); 198 199 // waiting for connection to succeed. 200 NDM_DEBUG("connect_to_ether_filter_manager: wait connection\n"); 201 while (soft_filters_connection == NULL) { 202 messages_wait_and_handle_next(); 203 } 204 205 // providing buffers for sending soft_filters 206 NDM_DEBUG("c_sf_mng: [%s] sharing memory\n", service_name); 207 share_common_memory_with_filter_manager(); 208 209 NDM_DEBUG("c_sf_mng: [%s] sharing memory\n", service_name); 210 211 sf_mac_lookup(); 212 213 printf("################################******\n"); 214 printf("For service [%s] MAC= %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", 215 service_name, mac.addr[0], mac.addr[1], mac.addr[2], 216 mac.addr[3], mac.addr[4], mac.addr[5]); 217 218} // end function: connect_soft_filters_manager 219 220 221// ***************************************************************** 222// * filter memory registration 223// * One time process 224// ***************************************************************** 225/** 226 * \brief sends cap to the memory which is to be shared between filter_manager 227 * of network driver and netd. 228 * 229 */ 230static void register_filter_memory(struct capref cap) 231{ 232 struct net_soft_filters_binding *b = soft_filters_connection; 233 234 errval_t err, rerr; 235 err = b->rpc_tx_vtbl.register_filter_memory(b, cap, &rerr); 236 assert(err_is_ok(err)); 237 assert(err_is_ok(rerr)); 238 soft_filters_ready = true; 239} 240 241 242/** 243* \brief: share the memory so that filter passing can be started. 244*/ 245static void share_common_memory_with_filter_manager(void) 246{ 247 errval_t err; 248 struct capref frame; 249 size_t size = BASE_PAGE_SIZE * 2; 250 size_t total_size = size * 7; 251 252 NDM_DEBUG("SCMWFM: started\n"); 253 254 NDM_DEBUG("SCMWFM: allocating %lu bytes of memory.\n", size); 255 256 err = bulk_create(total_size, size, &frame, &bt_filter_tx); 257 258 assert(err_is_ok(err)); 259 260 NDM_DEBUG("SCMWFM: registering netd filter memory\n"); 261 register_filter_memory(frame); 262 NDM_DEBUG("SCMWFM: terminated\n"); 263 264 // waiting for connection to succeed. 265 NDM_DEBUG("connect_to_ether_filter_manager: wait connection\n"); 266 while (!soft_filters_ready) { 267 messages_wait_and_handle_next(); 268 } 269 270 filter_mem_lock = false; // marking memory as ready to use 271} // end function: share_common_memory_with_filter_manager 272 273// Support code to convert mac address from uint64_t into eth_addr type 274union mac_addr_un1 { 275 struct eth_addr ethaddr; 276 uint64_t mac_addr; 277}; 278 279static struct eth_addr my_convert_uint64_to_eth_addr(uint64_t given_mac) 280{ 281 union mac_addr_un1 tmp_mac; 282 tmp_mac.mac_addr = given_mac; 283 284 // FIXME: make sure that this works irrespective of endianness of a machine 285 return tmp_mac.ethaddr; 286} 287 288// lookup the mac address 289static void sf_mac_lookup(void) 290{ 291 struct net_soft_filters_binding *b = soft_filters_connection; 292 293 uint64_t mac_addr; 294 errval_t err, rerr; 295 err = b->rpc_tx_vtbl.mac_address(b, &rerr, &mac_addr); 296 assert(err_is_ok(err)); 297 assert(err_is_ok(rerr)); 298 mac = my_convert_uint64_to_eth_addr(mac_addr); 299 valid_mac_addr_assigned = true; 300} // end function: sf_mac_lookup 301 302/** 303 * \brief sends the filter for registration to network driver. 304 * 305 */ 306static void send_soft_filter(uint64_t id, uint64_t len_rx, 307 uint64_t len_tx, uint64_t buffer_id_rx, 308 uint64_t buffer_id_tx, uint8_t ftype, 309 uint8_t paused, 310 errval_t *rerr, uint64_t *filter_id) 311{ 312 NDM_DEBUG("send_soft_filter: called for id %" PRIu64 313 " and type %x, paused = %d\n", id, ftype, paused); 314 315 struct net_soft_filters_binding *b = soft_filters_connection; 316 317 errval_t err; 318 err = b->rpc_tx_vtbl.register_filter(b, id, len_rx, len_tx, buffer_id_rx, buffer_id_tx, ftype, paused, rerr, filter_id); 319 assert(err_is_ok(err)); 320 assert(err_is_ok(*rerr)); 321 NDM_DEBUG("filter at id [%" PRIu64 "] type[%" PRIu64 322 "] registered with filt_id %" PRIu64 ".\n", id, ftype, 323 filter_id); 324 325 /* free the memory in shared area */ 326 err = bulk_free(&bt_filter_tx, id); 327 assert(err_is_ok(err)); 328 329 filter_mem_lock = false; // NOTE: filter memory can be used by others now 330} // end function: send_soft_filter 331 332/** 333 * \brief sends the filterID for de-registration to network driver. 334 * 335 */ 336static errval_t unregister_soft_filter(uint64_t filter_id, qid_t qid) 337{ 338 struct net_soft_filters_binding *b = soft_filters_connection; 339 340 errval_t err, rerr; 341 err = b->rpc_tx_vtbl.deregister_filter(b, filter_id, &rerr); 342 assert(err_is_ok(err)); 343 assert(err_is_ok(rerr)); 344 return rerr; 345} // end function: unregister_soft_filter 346 347/** 348 * \brief sends the filter for registration to network driver. 349 * 350 */ 351static void register_arp_soft_filter(uint64_t id, uint64_t len_rx, 352 uint64_t len_tx) 353{ 354 NDM_DEBUG("register_arp_soft_filter: called\n"); 355 struct net_soft_filters_binding *b = soft_filters_connection; 356 357 errval_t err, rerr; 358 err = b->rpc_tx_vtbl.register_arp_filter(b, id, len_rx, len_tx, &rerr); 359 assert(err_is_ok(err)); 360 assert(err_is_ok(rerr)); 361 362} // end function: register_arp_soft_filter 363 364static uint64_t populate_rx_tx_filter_mem(uint16_t port, net_ports_port_type_t type, 365 int32_t * len_rx, int32_t * len_tx) 366{ 367 368 struct bulk_buf *bb; 369 370 /* get memory chunk from shared memory */ 371 do { 372 bb = bulk_alloc(&bt_filter_tx); 373 if (bb == NULL) { 374 // dispatch one 375 NDM_DEBUG("bulk_alloc is returning NULL!!!! for filter memory\n"); 376 event_dispatch(get_default_waitset()); 377 } 378 } while (bb == NULL); 379 void *bbuf = bulk_buf_get_mem(bb); 380 381 382 uint8_t *filter_mem = NULL; 383 char *filter; 384 385 386 // rx filter 387 if (type == net_ports_PORT_TCP) { 388 filter = build_ether_dst_ipv4_tcp_filter(mac, 389 BFDMUX_IP_ADDR_ANY, 390 htonl(local_ip.addr), 391 PORT_ANY, 392 (port_t) port 393 ); 394 } else { 395 filter = build_ether_dst_ipv4_udp_filter(mac, 396 BFDMUX_IP_ADDR_ANY, 397 htonl(local_ip.addr), 398 PORT_ANY, 399 (port_t) port 400 ); 401 } 402 /* FIXME: shouldn't be above two ports be wrapped in htons(port)? */ 403// printf("##### The created filter is [%s]\n", filter); 404 compile_filter(filter, &filter_mem, len_rx); 405 assert(*len_rx < BASE_PAGE_SIZE); 406 407 assert(filter_mem != NULL); 408 memcpy(bbuf, filter_mem, *len_rx); 409 free(filter); 410 free(filter_mem); 411 412 // tx filter 413 if (type == net_ports_PORT_TCP) { 414 filter = build_ether_src_ipv4_tcp_filter(mac, htonl(local_ip.addr), 415 BFDMUX_IP_ADDR_ANY, 416 (port_t) port, PORT_ANY); 417 } else { 418 filter = build_ether_src_ipv4_udp_filter(mac, htonl(local_ip.addr), 419 BFDMUX_IP_ADDR_ANY, 420 (port_t) port, PORT_ANY); 421 } 422 compile_filter(filter, &filter_mem, len_tx); 423 assert(*len_tx < BASE_PAGE_SIZE); 424 425 void *bbuf_tx = bbuf + BASE_PAGE_SIZE; 426 427 memcpy(bbuf_tx, filter_mem, *len_tx); 428 429 free(filter); 430 free(filter_mem); 431 uint64_t id = bulk_prepare_send(bb); 432 433 return id; 434} 435