1/* 2 * Copyright (c) 2017, 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, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10 11#include <stdio.h> 12#include <stdlib.h> 13#include <string.h> 14 15#include <barrelfish/barrelfish.h> 16#include <barrelfish/nameservice_client.h> 17#include <if/net_filter_defs.h> 18#include <if/net_filter_rpcclient_defs.h> 19 20#include <net/net_filter.h> 21 22#include "networking_internal.h" 23#include "debug.h" 24 25#define MAX_NAME 128 26 27#define NETDEBUG_SUBSYSTEM "filter" 28 29/****************************************************************************** 30 * Connection setup 31 ******************************************************************************/ 32 33// Callback for bind 34static void bind_cb(void *st, errval_t err, struct net_filter_binding *b) 35{ 36 struct net_filter_state* filt = (struct net_filter_state*) st; 37 assert(err_is_ok(err)); 38 39 NETDEBUG("Sucessfully connected to management interface\n"); 40 41 filt->b = b; 42 net_filter_rpc_client_init(filt->b); 43 filt->bound = true; 44} 45 46 47/** Open connection to management interface */ 48static errval_t connect_to_net_filter(struct net_filter_state* st, 49 const char *dev_name) 50{ 51 errval_t r; 52 iref_t iref; 53 const char* prefix = "net_filter_"; 54 char name[strlen(dev_name) + strlen(prefix) + 1]; 55 56 // Build label for management service 57 sprintf(name, "%s%s", prefix, dev_name); 58 59 NETDEBUG("Name lookup\n"); 60 // Connect to service 61 r = nameservice_blocking_lookup(name, &iref); 62 if (err_is_fail(r)) { 63 return r; 64 } 65 66 NETDEBUG("Binding\n"); 67 r = net_filter_bind(iref, bind_cb, st, get_default_waitset(), 68 IDC_BIND_FLAGS_DEFAULT); 69 if (err_is_fail(r)) { 70 return r; 71 } 72 73 NETDEBUG("Waiting to bind\n"); 74 while(st->bound == false) { 75 event_dispatch(get_default_waitset()); 76 } 77 78 NETDEBUG("finished connecting\n"); 79 return SYS_ERR_OK; 80} 81 82 83/** Open connection to management interface */ 84static errval_t connect_to_net_filter_ep(struct net_filter_state* st, 85 struct capref ep) 86{ 87 errval_t r; 88 89 NETDEBUG("Binding\n"); 90 r = net_filter_bind_to_endpoint(ep, bind_cb, st, get_default_waitset(), 91 IDC_BIND_FLAGS_DEFAULT); 92 if (err_is_fail(r)) { 93 return r; 94 } 95 96 NETDEBUG("Waiting to bind\n"); 97 while(st->bound == false) { 98 event_dispatch(get_default_waitset()); 99 } 100 101 NETDEBUG("finished connecting\n"); 102 return SYS_ERR_OK; 103} 104 105/****************************************************************************** 106 * Helper functions 107 ******************************************************************************/ 108 109static bool filter_cmp_ip(struct net_filter_ip* f1, struct net_filter_ip* f2) 110{ 111 if (f1->ip_src == f2->ip_src && 112 f1->ip_dst == f2->ip_dst && 113 f1->port_src == f2->port_src && 114 f1->port_dst == f2->port_dst && 115 f1->qid == f2->qid && 116 f1->type == f2->type) { 117 return true; 118 } 119 return false; 120} 121 122/* 123static bool filter_cmp_mac(struct net_filter_mac* f1, struct net_filter_mac* f2) 124{ 125 if (f1->vlan_id == f2->vlan_id && 126 f1->mac == f2->mac && 127 f1->type == f2->type) { 128 return true; 129 } 130 return false; 131} 132*/ 133/* 134static bool is_reachable(struct net_filter_ip* filt) 135{ 136 struct net_filter_ele* cur = filter_state.filters_ip.start; 137 138 while(cur != NULL) { 139 printf("reachable: port_dst: %"PRIu16" %"PRIu16" \n", cur->filter.ip.port_dst, filt->port_dst); 140 if (filter_cmp_ip(&cur->filter.ip, filt)) { 141 return true; 142 } 143 cur = cur->next; 144 } 145 return false; 146} 147*/ 148/****************************************************************************** 149 * Library function implementation 150 ******************************************************************************/ 151 152/** 153 * @brief initalized network filtering. Sets up connection to drivers 154 * which support hardware filtering 155 * 156 * @param st returned net filter state; 157 * @param cardname the card name to be used 158 * 159 * @return SYS_ERR_OK on success, error on failure 160 */ 161errval_t net_filter_init(struct net_filter_state** st, 162 const char* cardname) 163{ 164 errval_t err; 165 166 struct net_filter_state* tmp = calloc(1, sizeof(struct net_filter_state)); 167 assert(tmp != NULL); 168 169 tmp->filters_ip.start = NULL; 170 tmp->filters_ip.num_ele = 0; 171 tmp->filters_mac.start = NULL; 172 tmp->filters_mac.num_ele = 0; 173 174 // cardname are of the form name:vendor:device:bus:function .. 175 int end = 0; 176 for (; end < strlen(cardname); end++) { 177 if (cardname[end] == ':') { 178 break; 179 } 180 } 181 182 char name[64]; 183 strncpy(name, cardname, end); 184 name[end] = '\0'; 185 186 printf("cardname %s \n", name); 187 err = connect_to_net_filter(tmp, name); 188 *st = tmp; 189 return err; 190} 191 192 193/** 194 * @brief initalized network filtering. Sets up connection to drivers 195 * which support hardware filtering 196 * 197 * @param st returned net filter state; 198 * @param ep endpoint to card used 199 * 200 * @return SYS_ERR_OK on success, error on failure 201 */ 202errval_t net_filter_init_with_ep(struct net_filter_state** st, 203 struct capref ep) 204{ 205 errval_t err; 206 207 struct net_filter_state* tmp = calloc(1, sizeof(struct net_filter_state)); 208 assert(tmp != NULL); 209 210 tmp->filters_ip.start = NULL; 211 tmp->filters_ip.num_ele = 0; 212 tmp->filters_mac.start = NULL; 213 tmp->filters_mac.num_ele = 0; 214 215 err = connect_to_net_filter_ep(tmp, ep); 216 *st = tmp; 217 return err; 218} 219 220 221/** 222 * @brief Installs an L3/L4 filter in the hardware filter 223 * tables 224 * 225 * @param st net filter state 226 * @param filt filter struct 227 * 228 * @return SYS_ERR_OK on success, error on failure 229 */ 230errval_t net_filter_ip_install(struct net_filter_state* st, 231 struct net_filter_ip* filt) 232{ 233 234 assert(st->bound); 235 errval_t err; 236 uint64_t filter_id; 237 238 struct net_filter_ele* cur = st->filters_ip.start; 239 struct net_filter_ele* prev = NULL; 240 241 /* go through linked list and find last element 242 (and check if filter is already installed) */ 243 if (cur == NULL) { 244 st->filters_ip.start = malloc(sizeof(struct net_filter_ele)); 245 cur = st->filters_ip.start; 246 } else { 247 while(cur->next != NULL) { 248 if (filter_cmp_ip(&cur->filter.ip, filt)) { 249 return NET_FILTER_ERR_ALREADY_EXISTS; 250 } 251 prev = cur; 252 cur = cur->next; 253 } 254 255 if (filter_cmp_ip(&cur->filter.ip, filt)) { 256 return NET_FILTER_ERR_ALREADY_EXISTS; 257 } 258 259 cur->next = malloc(sizeof(struct net_filter_ele)); 260 cur = cur->next; 261 } 262 263 cur->filter.ip.ip_src = filt->ip_src; 264 cur->filter.ip.ip_dst = filt->ip_dst; 265 cur->filter.ip.port_src = filt->port_src; 266 cur->filter.ip.port_dst = filt->port_dst; 267 cur->filter.ip.qid = filt->qid; 268 cur->filter.ip.type = filt->type; 269 cur->next = NULL; 270 cur->prev = prev; 271 272 st->filters_ip.num_ele++; 273 274 err = st->b->rpc_tx_vtbl.install_filter_ip(st->b, 275 filt->type, 276 filt->qid, 277 filt->ip_src, 278 filt->ip_dst, 279 filt->port_src, 280 filt->port_dst, 281 &filter_id); 282 if (err_is_fail(err)) { 283 free(cur); 284 return err; 285 } 286 287 cur->filter_id = filter_id; 288 return SYS_ERR_OK; 289} 290 291 292/** 293 * @brief Removes an L3/L4 filter in the hardware filter 294 * tables 295 * 296 * @param st net filter state 297 * @param filt filter struct 298 * 299 * @return SYS_ERR_OK on success, error on failure 300 */ 301errval_t net_filter_ip_remove(struct net_filter_state* st, 302 struct net_filter_ip* filt) 303{ 304 305 assert(st->bound); 306 errval_t err, err2; 307 uint64_t filter_id = (uint64_t)-1; 308 309 struct net_filter_ele* cur = st->filters_ip.start; 310 struct net_filter_ele* prev = NULL; 311 312 313 // no entries 314 if (cur == NULL) { 315 return NET_FILTER_ERR_NOT_FOUND; 316 } 317 318 // Multiple entries 319 while(cur != NULL) { 320 if (filter_cmp_ip(&cur->filter.ip, filt)) { 321 filter_id = cur->filter_id; 322 break; 323 } 324 prev = cur; 325 cur = cur->next; 326 } 327 328 329 if (filter_id == (uint64_t) -1) { 330 return NET_FILTER_ERR_NOT_FOUND; 331 } 332 333 err = st->b->rpc_tx_vtbl.remove_filter(st->b, 334 filt->type, 335 filter_id, 336 &err2); 337 if (err_is_fail(err) || err_is_fail(err2)) { 338 return err_is_fail(err) ? err: err2; 339 } 340 341 // remove from queue 342 if (prev != NULL) { // check if first 343 prev->next = cur->next; 344 if (cur->next != NULL) { // check if last 345 cur->next->prev = prev; 346 } 347 } else { 348 st->filters_ip.start = cur->next; 349 } 350 351 352 free(cur); 353 354 st->filters_ip.num_ele--; 355 356 return SYS_ERR_OK; 357} 358 359errval_t net_filter_mac_install(struct net_filter_state* st, 360 struct net_filter_mac* filt) 361{ 362 USER_PANIC("NYI \n"); 363} 364 365 366errval_t net_filter_mac_remove(struct net_filter_state* st, 367 struct net_filter_mac* filt) 368{ 369 USER_PANIC("NYI \n"); 370} 371