diff options
author | Timo Teras <timo.teras@iki.fi> | 2008-12-29 13:47:41 +0200 |
---|---|---|
committer | Timo Teras <timo.teras@iki.fi> | 2008-12-29 13:47:41 +0200 |
commit | dbe877cdca9a693462d776dd978592ed1068da0f (patch) | |
tree | 7907bd5d64750e5d15439cd7e533c2a7f826895f | |
parent | cab8b9de73a8471ae69485dddebfa1e91c0a28eb (diff) | |
download | pingu-dbe877cdca9a693462d776dd978592ed1068da0f.tar.bz2 pingu-dbe877cdca9a693462d776dd978592ed1068da0f.tar.xz |
mtu: write discovered mtu to interface mtu
-rw-r--r-- | mtu.c | 74 | ||||
-rw-r--r-- | netlink.c | 54 | ||||
-rw-r--r-- | netlink.h | 2 |
3 files changed, 110 insertions, 20 deletions
@@ -5,6 +5,8 @@ #include <string.h> #include <unistd.h> +#include <linux/if.h> +#include <linux/sockios.h> #include <netinet/ip_icmp.h> #include "icmp.h" @@ -17,7 +19,8 @@ static void usage(void) fprintf(stderr, "usage: mtu -i <mtu-size> <host>\n" " mtu -I <host>\n" - " mtu -d <host>\n"); + " mtu -d <host>\n" + " mtu -D <host>\n"); exit(3); } @@ -58,16 +61,14 @@ static int do_ping(int seq, int size) return -1; } -static void do_discover(void) +static int discover_mtu(void) { int seq = 1; int low_mtu, high_mtu, try_mtu; /* Check if the host is up */ - if (do_ping(seq++, 0) < 0) { - fprintf(stderr, "Host is not up\n"); - return; - } + if (do_ping(seq++, 0) < 0) + return -1; /* Check if there is no PMTU or if PMTU discovery works */ low_mtu = do_ping(seq++, 1500); @@ -85,7 +86,59 @@ static void do_discover(void) low_mtu = 1500; } - fprintf(stdout, "%d\n", low_mtu); + return low_mtu; +} + +static void do_discover(void) +{ + int mtu; + + mtu = discover_mtu(); + if (mtu > 0) + fprintf(stdout, "%d\n", mtu); + else + fprintf(stderr, "Host is not up\n"); +} + +static int set_mtu(const char *dev, int mtu) +{ + struct ifreq ifr; + int fd; + + fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) + return -1; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + ifr.ifr_mtu = mtu; + if (ioctl(fd, SIOCSIFMTU, &ifr) < 0) { + perror("SIOCSIFMTU"); + close(fd); + return -1; + } + close(fd); + return 0; +} + +static void do_discover_and_write(void) +{ + int mtu; + char iface[IFNAMSIZ]; + + mtu = discover_mtu(); + if (mtu < 0) { + fprintf(stderr, "Failed to determine MTU\n"); + return; + } + + if (!netlink_route_get(&to, NULL, iface)) { + fprintf(stderr, "Failed to determine route interface\n"); + return; + } + + printf("Writing %d to %s\n", mtu, iface); + set_mtu(iface, mtu); } static void do_inject(void) @@ -121,7 +174,7 @@ static void do_inject_pmtu(void) { u_int16_t mtu; - if (netlink_route_get(&to, &mtu) < 0) { + if (!netlink_route_get(&to, &mtu, NULL)) { fprintf(stderr, "Failed to determine Path MTU\n"); return; } @@ -139,8 +192,11 @@ int main(int argc, char **argv) char *target; int opt; - while ((opt = getopt(argc, argv, "dIi:")) != -1) { + while ((opt = getopt(argc, argv, "DdIi:")) != -1) { switch (opt) { + case 'D': + action = do_discover_and_write; + break; case 'd': action = do_discover; break; @@ -220,16 +220,21 @@ out: return ret; } -int netlink_route_get(struct sockaddr *dst, u_int16_t *mtu) +int netlink_route_get(struct sockaddr *dst, u_int16_t *mtu, char *ifname) { struct { struct nlmsghdr n; - struct rtmsg r; + union { + struct rtmsg r; + struct ifinfomsg i; + }; char buf[1024]; } req; struct rtmsg *r = NLMSG_DATA(&req.n); struct rtattr *rta[RTA_MAX+1]; struct rtattr *rtax[RTAX_MAX+1]; + struct rtattr *ifla[IFLA_MAX+1]; + int index; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); @@ -243,15 +248,44 @@ int netlink_route_get(struct sockaddr *dst, u_int16_t *mtu) if (!netlink_talk(&req.n, sizeof(req), &req.n)) return FALSE; - netlink_parse_rtattr(rta, RTA_MAX, RTM_RTA(r), RTM_PAYLOAD(&req.n)); - if (rta[RTA_METRICS] == NULL) - return FALSE; + netlink_parse_rtattr(rta, RTA_MAX, RTM_RTA(r), + RTM_PAYLOAD(&req.n)); - netlink_parse_rtattr(rtax, RTAX_MAX, RTA_DATA(rta[RTA_METRICS]), - RTA_PAYLOAD(rta[RTA_METRICS])); - if (rtax[RTAX_MTU] == NULL) - return FALSE; + if (mtu != NULL) { + if (rta[RTA_METRICS] == NULL) + return FALSE; + + netlink_parse_rtattr(rtax, RTAX_MAX, + RTA_DATA(rta[RTA_METRICS]), + RTA_PAYLOAD(rta[RTA_METRICS])); + if (rtax[RTAX_MTU] == NULL) + return FALSE; + + *mtu = *(int*) RTA_DATA(rtax[RTAX_MTU]); + } + + if (ifname != NULL) { + if (rta[RTA_OIF] == NULL) + return FALSE; + + index = *(int*) RTA_DATA(rta[RTA_OIF]); + + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_GETLINK; + req.i.ifi_index = index; + if (!netlink_talk(&req.n, sizeof(req), &req.n)) + return FALSE; + + netlink_parse_rtattr(ifla, IFLA_MAX, IFLA_RTA(r), + IFLA_PAYLOAD(&req.n)); + if (ifla[IFLA_IFNAME] == NULL) + return FALSE; + + memcpy(ifname, RTA_DATA(ifla[IFLA_IFNAME]), + RTA_PAYLOAD(ifla[IFLA_IFNAME])); + } - *mtu = *(int*) RTA_DATA(rtax[RTAX_MTU]); return TRUE; } @@ -1,6 +1,6 @@ #ifndef PINGU_NETLINK_H #define PINGU_NETLINK_H -int netlink_route_get(struct sockaddr *dst, u_int16_t *mtu); +int netlink_route_get(struct sockaddr *dst, u_int16_t *mtu, char *ifname); #endif |