diff options
author | Jordan Augé <jordan.auge+fdio@cisco.com> | 2019-07-26 23:20:30 +0200 |
---|---|---|
committer | Mauro Sardara <msardara@cisco.com> | 2019-07-29 17:13:35 +0200 |
commit | 0a1c6b5565e20167d1f1f33a5a8b597f420b18b0 (patch) | |
tree | 98c5da8f231fbd3dc2ce6502040e29c8333d9ffc /ctrl/facemgr/src/interfaces/netlink | |
parent | 05ca0aa8f612ee48fb66d4dbebe596b7f1e03181 (diff) |
[HICN-252] Add per-application policy framework to hicn-light forwarder
Change-Id: I0531cd7a7de179581295ae34766c81cd9cf3e172
Signed-off-by: Jordan Augé <jordan.auge+fdio@cisco.com>
Signed-off-by: Mauro Sardara <msardara@cisco.com>
Co-authored-by: Mauro Sardara <msardara@cisco.com>
Diffstat (limited to 'ctrl/facemgr/src/interfaces/netlink')
-rw-r--r-- | ctrl/facemgr/src/interfaces/netlink/CMakeLists.txt | 30 | ||||
-rw-r--r-- | ctrl/facemgr/src/interfaces/netlink/netlink.c | 254 |
2 files changed, 284 insertions, 0 deletions
diff --git a/ctrl/facemgr/src/interfaces/netlink/CMakeLists.txt b/ctrl/facemgr/src/interfaces/netlink/CMakeLists.txt new file mode 100644 index 000000000..7f44d87fe --- /dev/null +++ b/ctrl/facemgr/src/interfaces/netlink/CMakeLists.txt @@ -0,0 +1,30 @@ +# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +list(APPEND HEADER_FILES +) + +list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/netlink.c +) + +list(APPEND LIBRARIES +) + +list(APPEND INCLUDE_DIRS +) + +set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) +set(INCLUDE_DIRS ${INCLUDE_DIRS} PARENT_SCOPE) +set(LIBRARIES ${LIBRARIES} PARENT_SCOPE) diff --git a/ctrl/facemgr/src/interfaces/netlink/netlink.c b/ctrl/facemgr/src/interfaces/netlink/netlink.c new file mode 100644 index 000000000..5bf0baf9f --- /dev/null +++ b/ctrl/facemgr/src/interfaces/netlink/netlink.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file interfaces/netlink/netlink.c + * \brief Netlink interface + */ + +#include <linux/rtnetlink.h> +#include <sys/types.h> // getpid +#include <unistd.h> // getpid + +#include "../../event.h" +#include "../../facemgr.h" +#include "../../interface.h" + +/* Internal data storage */ +typedef struct { + int fd; +} nl_data_t; + +// little helper to parsing message using netlink macroses +void parseRtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) +{ + memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); + + while (RTA_OK(rta, len)) { // while not end of the message + if (rta->rta_type <= max) { + tb[rta->rta_type] = rta; // read attr + } + rta = RTA_NEXT(rta,len); // get next attr + } +} + + +int nl_initialize(interface_t * interface, face_rules_t * rules, void ** pdata) +{ + nl_data_t * data = malloc(sizeof(nl_data_t)); + if (!data) + goto ERR_MALLOC; + + data->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (data->fd < 0) { + printf("Failed to create netlink socket: %s\n", (char*)strerror(errno)); + goto ERR_SOCKET; + } + + struct sockaddr_nl local; // local addr struct + memset(&local, 0, sizeof(local)); + local.nl_family = AF_NETLINK; // set protocol family + local.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE; // set groups we interested in + local.nl_pid = getpid(); // set out id using current process id + + + if (bind(data->fd, (struct sockaddr*)&local, sizeof(local)) < 0) { // bind socket + printf("Failed to bind netlink socket: %s\n", (char*)strerror(errno)); + goto ERR_BIND; + } + + /* Issue a first query to receive static state */ + + + *pdata = data; + return data->fd; // FACEMGR_SUCCESS; + +ERR_BIND: + close(data->fd); +ERR_SOCKET: + free(data); +ERR_MALLOC: + *pdata = NULL; + return FACEMGR_FAILURE; +} + +int nl_callback(interface_t * interface) +{ + nl_data_t * data = (nl_data_t*)interface->data; + + struct sockaddr_nl local; // local addr struct + memset(&local, 0, sizeof(local)); + + char buf[8192]; // message buffer + struct iovec iov; // message structure + iov.iov_base = buf; // set message buffer as io + iov.iov_len = sizeof(buf); // set size + + // initialize protocol message header + struct msghdr msg; + { + msg.msg_name = &local; // local address + msg.msg_namelen = sizeof(local); // address size + msg.msg_iov = &iov; // io vector + msg.msg_iovlen = 1; // io size + } + + ssize_t status = recvmsg(data->fd, &msg, 0); + + // check status + if (status < 0) { +/* + if (errno == EINTR || errno == EAGAIN) + continue; +*/ + + printf("Failed to read netlink: %s", (char*)strerror(errno)); + return FACEMGR_FAILURE; + } + + if (msg.msg_namelen != sizeof(local)) { // check message length, just in case + printf("Invalid length of the sender address struct\n"); + return FACEMGR_FAILURE; + } + + // message parser + struct nlmsghdr *h; + + for (h = (struct nlmsghdr*)buf; status >= (ssize_t)sizeof(*h); ) { // read all messagess headers + int len = h->nlmsg_len; + int l = len - sizeof(*h); + char *ifName = NULL; + + if ((l < 0) || (len > status)) { + printf("Invalid message length: %i\n", len); + continue; + } + + // now we can check message type + if ((h->nlmsg_type == RTM_NEWROUTE) || (h->nlmsg_type == RTM_DELROUTE)) { // some changes in routing table + printf("Routing table was changed\n"); + } else { // in other case we need to go deeper + char *ifUpp; + char *ifRunn; + struct ifinfomsg *ifi; // structure for network interface info + struct rtattr *tb[IFLA_MAX + 1]; + + ifi = (struct ifinfomsg*) NLMSG_DATA(h); // get information about changed network interface + + parseRtattr(tb, IFLA_MAX, IFLA_RTA(ifi), h->nlmsg_len); // get attributes + + if (tb[IFLA_IFNAME]) { // validation + ifName = (char*)RTA_DATA(tb[IFLA_IFNAME]); // get network interface name + } + + if (ifi->ifi_flags & IFF_UP) { // get UP flag of the network interface + ifUpp = (char*)"UP"; + } else { + ifUpp = (char*)"DOWN"; + } + + if (ifi->ifi_flags & IFF_RUNNING) { // get RUNNING flag of the network interface + ifRunn = (char*)"RUNNING"; + } else { + ifRunn = (char*)"NOT RUNNING"; + } + + char ifAddress[256] = {0}; // network addr + struct ifaddrmsg *ifa; // structure for network interface data + struct rtattr *tba[IFA_MAX+1]; + + ifa = (struct ifaddrmsg*)NLMSG_DATA(h); // get data from the network interface + + parseRtattr(tba, IFA_MAX, IFA_RTA(ifa), h->nlmsg_len); + + if (tba[IFA_LOCAL]) { + inet_ntop(AF_INET, RTA_DATA(tba[IFA_LOCAL]), ifAddress, sizeof(ifAddress)); // get IP addr + } + + face_t * face; + + if (tba[IFA_LOCAL]) { + ip_address_t local_addr = IP_ADDRESS_EMPTY; + switch(ifa->ifa_family) { + case AF_INET: + local_addr.v4.as_inaddr = *(struct in_addr*)RTA_DATA(tba[IFA_LOCAL]); + break; + case AF_INET6: + local_addr.v6.as_in6addr = *(struct in6_addr*)RTA_DATA(tba[IFA_LOCAL]); + break; + default: + continue; + } + face = face_create_udp(&local_addr, 0, &IP_ADDRESS_EMPTY, 0, ifa->ifa_family); + } else { + face = NULL; + } + + switch (h->nlmsg_type) { + case RTM_DELADDR: + // DOES NOT SEEM TO BE TRIGGERED + printf("Interface %s: address was removed\n", ifName); + if (face) + event_raise(EVENT_TYPE_DELETE, face, interface); + break; + + case RTM_DELLINK: + printf("Network interface %s was removed\n", ifName); + break; + + case RTM_NEWLINK: + printf("New network interface %s, state: %s %s\n", ifName, ifUpp, ifRunn); + // UP RUNNING + // UP NOT RUNNING + // DOWN NOT RUNNING + if (!(ifi->ifi_flags & IFF_UP) || (!(ifi->ifi_flags & IFF_RUNNING))) { + if(face) + event_raise(EVENT_TYPE_DELETE, face, interface); + } + break; + + case RTM_NEWADDR: + printf("Interface %s: new address was assigned: %s\n", ifName, ifAddress); + printf("NEW FACE\n"); + if (face) + event_raise(EVENT_TYPE_CREATE, face, interface); + break; + } + } + + status -= NLMSG_ALIGN(len); // align offsets by the message length, this is important + + h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); // get next message + } + + return FACEMGR_SUCCESS; +} + +int nl_finalize(interface_t * interface) +{ + nl_data_t * data = (nl_data_t*)interface->data; + close(data->fd); + return FACEMGR_SUCCESS; + +} + +const interface_ops_t netlink_ops = { + .type = "netlink", + .is_singleton = true, + .initialize = nl_initialize, + .callback = nl_callback, + .finalize = nl_finalize, + .on_event = NULL, +}; |